Fixing nested horizontal scrollview scrolling on Android (#39097)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/39097

Changelog:
[Internal][Added] - Created mechanism to have nested horizontal scrollviews (or flatlists/sectionlists) by prioritizing scrolling on deeper nested scrollviews which have the enableNestedScroll prop equal to true.

Reviewed By: NickGerleman

Differential Revision: D48504762

fbshipit-source-id: 1a6d01f68e142d99ea494e2b5630979c7be2ecce
This commit is contained in:
Jesse Watts-Russell
2023-08-22 07:30:44 -07:00
committed by Facebook GitHub Bot
parent 08f0cda867
commit 211f3145db
@@ -471,12 +471,65 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
}
}
@Nullable
private static HorizontalScrollView findDeepestScrollViewForMotionEvent(
View view, MotionEvent ev) {
return findDeepestScrollViewForMotionEvent(view, ev, true);
}
@Nullable
private static HorizontalScrollView findDeepestScrollViewForMotionEvent(
View view, MotionEvent ev, boolean skipInitialView) {
if (view == null) {
return null;
}
Rect rectOnScreen = new Rect();
view.getGlobalVisibleRect(rectOnScreen);
if (!rectOnScreen.contains((int) ev.getRawX(), (int) ev.getRawY())) {
return null;
}
// Only consider the current view if it's not the initial view. We check the
// current view first to bail out of recursion. Essentially if there's any
// nested horizontal scrollview with nested scrolling enabled, the parent
// scroll view shouldn't pick up the down event.
if (!skipInitialView
&& view instanceof HorizontalScrollView
&& ViewCompat.isNestedScrollingEnabled(view)
&& (view instanceof ReactHorizontalScrollView
&& ((ReactHorizontalScrollView) view).mScrollEnabled)) {
return (HorizontalScrollView) view;
}
// First, check child views recursively before considering this view.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
HorizontalScrollView foundScrollView =
findDeepestScrollViewForMotionEvent(((ViewGroup) view).getChildAt(i), ev, false);
if (foundScrollView != null) {
// If a deeper HorizontalScrollView is found in child views, return it.
return foundScrollView;
}
}
}
// Return null if no matching view is found.
return null;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!mScrollEnabled) {
return false;
}
if ((ev.getAction() == MotionEvent.ACTION_DOWN)
&& findDeepestScrollViewForMotionEvent(this, ev) != null) {
return false;
}
// We intercept the touch event if the children are not supposed to receive it.
if (!PointerEvents.canChildrenBeTouchTarget(mPointerEvents)) {
return true;