From 0bd09c046a0fcea4a642f841f01bff4c4f394909 Mon Sep 17 00:00:00 2001 From: Xin Chen Date: Thu, 16 Dec 2021 17:13:51 -0800 Subject: [PATCH] Change touch target lookup to exclude overflow hidden view group Summary: In D30104853 (https://github.com/facebook/react-native/commit/e35a963bfb93bbbdd92f4dd74d14e2ad6df5e14a), 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 --- .../react/uimanager/TouchTargetHelper.java | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java index bf9a6207c77254..2fdbe18d643480 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java @@ -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. @@ -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;