Skip to content

Commit

Permalink
[Android] Try to disambiguate taps from swipes (#7448)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaearon authored Jan 15, 2025
1 parent 479a4a9 commit 96054f4
Showing 1 changed file with 40 additions and 2 deletions.
42 changes: 40 additions & 2 deletions src/view/com/pager/Pager.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {forwardRef, useCallback, useContext} from 'react'
import React, {Children, 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,6 +17,7 @@ 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 @@ -148,14 +149,51 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
style={[a.flex_1]}
initialPage={initialPage}
onPageScroll={handlePageScroll}>
{children}
{isAndroid
? Children.map(children, child => (
<CaptureSwipesAndroid>{child}</CaptureSwipesAndroid>
))
: 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 96054f4

Please sign in to comment.