Skip to content

Commit

Permalink
Change touch target lookup to exclude overflow hidden view group
Browse files Browse the repository at this point in the history
Summary:
In D30104853 (facebook@e35a963), we added fix to the issue where touches on the child view that is outside of its parent view's boundary are not registered. The only exception to that is if the parent view has overflow style `overflow: hidden`. In that case, touches happen outside of the parent view should be ignored.

{F686521911}

That fix works, but it increases the complexity for the DFS algorithm used to find the touch target in two ways:

1. Before we only traverse views that contain the touch event point. If the touch event point is outside of the view, we won't step in and traverse that part of the tree. This is actually what caused the initial problem. The fix removed that boundary check (where `isTransformedTouchPointInView` used to do) and push it later. This increases the number of tree traversal a lot.
2. The check for `overflow: hidden` is happened after we find a potential target view, which means we've spent time to find the target view before we decide if the target view is even a candidate.

This diff aims to update for the #2 item above. Since we are checking the style of the parent view, not the target view, it's not necessary to check that after we find the target view. We could check the parent view and if it has `overflow: hidden` on it, any pointer event that are not in the boundary can be ignored already.

Changelog:
[Internal][Android]

Reviewed By: mdvacca, ShikaSD

Differential Revision: D33079157

fbshipit-source-id: c79c2b38b8affb9ea0fd25b5e880b22466ab7ed9
  • Loading branch information
ryancat authored and facebook-github-bot committed Dec 17, 2021
1 parent 41cad35 commit 0bd09c0
Showing 1 changed file with 11 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@ private static View findTouchTargetView(
// We prefer returning a child, so we check for a child that can handle the touch first
if (allowReturnTouchTargetTypes.contains(TouchTargetReturnType.CHILD)
&& view instanceof ViewGroup) {
// We don't allow touches on views that are outside the bounds of an `overflow: hidden` and
// `overflow: scroll` View.
if (view instanceof ReactOverflowView) {
@Nullable String overflow = ((ReactOverflowView) view).getOverflow();
if ((ViewProps.HIDDEN.equals(overflow) || ViewProps.SCROLL.equals(overflow))
&& !isTouchPointInView(eventCoords[0], eventCoords[1], view)) {
return null;
}
}

ViewGroup viewGroup = (ViewGroup) view;
int childrenCount = viewGroup.getChildCount();
// Consider z-index when determining the touch target.
Expand All @@ -198,22 +208,7 @@ private static View findTouchTargetView(
eventCoords[1] = childPoint.y;
View targetView = findTouchTargetViewWithPointerEvents(eventCoords, child, pathAccumulator);
if (targetView != null) {
// We don't allow touches on views that are outside the bounds of an `overflow: hidden`
// View
boolean inOverflowBounds = true;
if (viewGroup instanceof ReactOverflowView) {
@Nullable String overflow = ((ReactOverflowView) viewGroup).getOverflow();
if ((ViewProps.HIDDEN.equals(overflow) || ViewProps.SCROLL.equals(overflow))
&& !isTouchPointInView(restoreX, restoreY, view)) {
inOverflowBounds = false;
}
}
if (inOverflowBounds) {
return targetView;
} else if (pathAccumulator != null) {
// Not a hit, reset the path found so far
pathAccumulator.clear();
}
return targetView;
}
eventCoords[0] = restoreX;
eventCoords[1] = restoreY;
Expand Down

0 comments on commit 0bd09c0

Please sign in to comment.