Intercept touch event for simulated joystick scrolling to avoid nested scroll view issues

Summary:
The issue to be fixed here is an edge case when in nested scroll view, for example vertical scroll wraps horizontal scroll, when user scrolls horizontally then move the joystick downwards, the horizontal scroll would bounce back. This is shown in the demo:

https://pxl.cl/209f8

The root cause of the issue is due to two workflows fight to set the scroll position and confusing the scroll change dispatcher to calculate fling velocity direction, which caused a wrong fling behavior. Check this log and description to get more details:

{F706620839}

To fix the issue, in this diff we overridden the `onInterceptTouchEvent` method in panel app scroll views, and make it return true when the previous scroll is still running. This effectively skips the drag slop in the default scroll view behavior, as we know the touch event should've been handled by the scroll view if it's still scrolling.

This way, the vertical scroll part on the vertical scroll view will not be dispatched to the horizontal scroll at all. This allows the nested scroll view to work separately.

Changelog:
[Android][Internal] - Share the post intercept touch event logic in scroll views

Reviewed By: javache

Differential Revision: D34627329

fbshipit-source-id: d500ec3bfbe349a45ef5c1360b5c8807c168f682
This commit is contained in:
Xin Chen
2022-03-04 15:50:00 -08:00
committed by Facebook GitHub Bot
parent 0368081858
commit 87ad1e8570
2 changed files with 18 additions and 10 deletions
@@ -460,11 +460,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
try {
if (super.onInterceptTouchEvent(ev)) {
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
ReactScrollViewHelper.emitScrollBeginDragEvent(this);
mDragging = true;
enableFpsListener();
getFlingAnimator().cancel();
handleInterceptedTouchEvent(ev);
return true;
}
} catch (IllegalArgumentException e) {
@@ -477,6 +473,14 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
return false;
}
protected void handleInterceptedTouchEvent(MotionEvent ev) {
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
ReactScrollViewHelper.emitScrollBeginDragEvent(this);
mDragging = true;
enableFpsListener();
getFlingAnimator().cancel();
}
@Override
public boolean pageScroll(int direction) {
boolean handled = super.pageScroll(direction);
@@ -340,11 +340,7 @@ public class ReactScrollView extends ScrollView
try {
if (super.onInterceptTouchEvent(ev)) {
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
ReactScrollViewHelper.emitScrollBeginDragEvent(this);
mDragging = true;
enableFpsListener();
getFlingAnimator().cancel();
handleInterceptedTouchEvent(ev);
return true;
}
} catch (IllegalArgumentException e) {
@@ -357,6 +353,14 @@ public class ReactScrollView extends ScrollView
return false;
}
protected void handleInterceptedTouchEvent(MotionEvent ev) {
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
ReactScrollViewHelper.emitScrollBeginDragEvent(this);
mDragging = true;
enableFpsListener();
getFlingAnimator().cancel();
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!mScrollEnabled) {