Skip to content

Commit

Permalink
Fixing nested horizontal scrollview scrolling on Android (#39097)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #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
  • Loading branch information
Jesse Watts-Russell authored and facebook-github-bot committed Aug 22, 2023
1 parent 08f0cda commit 211f314
Showing 1 changed file with 53 additions and 0 deletions.
Expand Up @@ -471,12 +471,65 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
}
}

@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;
Expand Down

0 comments on commit 211f314

Please sign in to comment.