Skip to content

Commit

Permalink
[Android] Fix taps triggering while swiping (#7459)
Browse files Browse the repository at this point in the history
* [Android] Fix taps triggering while swiping

* Revert "[Android] Try to disambiguate taps from swipes (#7448)"

This reverts commit 96054f4.

* Update patch to match callstack/react-native-pager-view#961

* Make it symmetrical

---------

Co-authored-by: Dan Abramov <[email protected]>
  • Loading branch information
gpp-0 and gaearon authored Jan 17, 2025
1 parent 9e3f2f4 commit 5130d19
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 40 deletions.
72 changes: 72 additions & 0 deletions patches/react-native-pager-view+6.6.1.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
diff --git a/node_modules/react-native-pager-view/android/build/tmp/kotlin-classes/debug/com/reactnativepagerview/NestedScrollableHost.class b/node_modules/react-native-pager-view/android/build/tmp/kotlin-classes/debug/com/reactnativepagerview/NestedScrollableHost.class
new file mode 100644
index 0000000..b64fccc
Binary files /dev/null and b/node_modules/react-native-pager-view/android/build/tmp/kotlin-classes/debug/com/reactnativepagerview/NestedScrollableHost.class differ
diff --git a/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt b/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt
index 91d9946..87b58d0 100644
--- a/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt
+++ b/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt
@@ -8,6 +8,7 @@ import android.view.ViewConfiguration
import android.widget.FrameLayout
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
+import com.facebook.react.uimanager.events.NativeGestureUtil
import kotlin.math.absoluteValue
import kotlin.math.sign

@@ -27,6 +28,7 @@ class NestedScrollableHost : FrameLayout {
private var touchSlop = 0
private var initialX = 0f
private var initialY = 0f
+ private var nativeGestureStarted: Boolean = false
private val parentViewPager: ViewPager2?
get() {
var v: View? = parent as? View
@@ -57,17 +59,14 @@ class NestedScrollableHost : FrameLayout {
}

private fun handleInterceptTouchEvent(e: MotionEvent) {
- val orientation = parentViewPager?.orientation ?: return
-
- // Early return if child can't scroll in same direction as parent
- if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) {
- return
- }
+ val orientation = parentViewPager?.orientation

if (e.action == MotionEvent.ACTION_DOWN) {
initialX = e.x
initialY = e.y
- parent.requestDisallowInterceptTouchEvent(true)
+ if (orientation != null) {
+ parent.requestDisallowInterceptTouchEvent(true)
+ }
} else if (e.action == MotionEvent.ACTION_MOVE) {
val dx = e.x - initialX
val dy = e.y - initialY
@@ -78,6 +77,10 @@ class NestedScrollableHost : FrameLayout {
val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f

if (scaledDx > touchSlop || scaledDy > touchSlop) {
+ NativeGestureUtil.notifyNativeGestureStarted(this, e)
+ nativeGestureStarted = true
+
+ if (orientation == null) return
if (isVpHorizontal == (scaledDy > scaledDx)) {
// Gesture is perpendicular, allow all parents to intercept
parent.requestDisallowInterceptTouchEvent(false)
@@ -94,4 +97,14 @@ class NestedScrollableHost : FrameLayout {
}
}
}
+
+ override fun onTouchEvent(e: MotionEvent): Boolean {
+ if (e.actionMasked == MotionEvent.ACTION_UP) {
+ if (nativeGestureStarted) {
+ NativeGestureUtil.notifyNativeGestureEnded(this, e)
+ nativeGestureStarted = false
+ }
+ }
+ return super.onTouchEvent(e)
+ }
}
42 changes: 2 additions & 40 deletions src/view/com/pager/Pager.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {Children, forwardRef, useCallback, useContext} from 'react'
import React, {forwardRef, useCallback, useContext} from 'react'
import {View} from 'react-native'
import {DrawerGestureContext} from 'react-native-drawer-layout'
import {Gesture, GestureDetector} from 'react-native-gesture-handler'
Expand All @@ -17,7 +17,6 @@ import Animated, {
} from 'react-native-reanimated'
import {useFocusEffect} from '@react-navigation/native'

import {isAndroid} from '#/platform/detection'
import {useSetDrawerSwipeDisabled} from '#/state/shell'
import {atoms as a, native} from '#/alf'

Expand Down Expand Up @@ -149,51 +148,14 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
style={[a.flex_1]}
initialPage={initialPage}
onPageScroll={handlePageScroll}>
{isAndroid
? Children.map(children, child => (
<CaptureSwipesAndroid>{child}</CaptureSwipesAndroid>
))
: children}
{children}
</AnimatedPagerView>
</GestureDetector>
</View>
)
},
)

// HACK.
// This works around https://github.com/callstack/react-native-pager-view/issues/960.
// It appears that the Pressables inside the pager get confused if there's enough work
// happening on the JS thread, and mistakingly interpret a pager swipe as a tap.
// We can prevent this by stealing all horizontal movements from the tree inside.
function CaptureSwipesAndroid({children}: {children: React.ReactNode}) {
const lastTouchStart = React.useRef<{x: number; y: number} | null>(null)
return (
<View
onTouchStart={e => {
lastTouchStart.current = {
x: e.nativeEvent.pageX,
y: e.nativeEvent.pageY,
}
}}
onMoveShouldSetResponderCapture={e => {
const coords = lastTouchStart.current
if (!coords) {
return false
}
const dx = Math.abs(e.nativeEvent.pageX - coords.x)
if (dx > 0) {
// This is a horizontal movement and will result in a swipe.
// Prevent pager children from receiving this touch.
return true
}
return false
}}>
{children}
</View>
)
}

function usePagerHandlers(
handlers: {
onPageScroll: (e: PagerViewOnPageScrollEventData) => void
Expand Down

0 comments on commit 5130d19

Please sign in to comment.