Nested Pan / LongPressGestureHandlers with different behavior Android / iOS
See original GitHub issueDescription
I’m trying to get a list (ScrollView) that contains items that can be reordered. I struggled a bit with the implementation, but got it working on iOS like with nested LongPress / PanGesture-Handlers:
I got both the Pan event and the ScrollView working on iOS by setting activeOffsetX
and activeOffsetY
as states, which are updated upon LongPress events. The offset defaults to [-100, 100]
, which causes flicks to scroll the all items on the ScrollView. After a long press, I set the offset to [0,0]
, and I can start dragging around the items on the UI. But as I said, that only works on iOS, so there’s another distinction between the platforms.
On Android, this doesn’t work at all. I noticed a few things:
- The LongPressEvent becomes active immediately, there is not delay at all (I can quickly flick on the UI, and the
OnActive
event fires). SettingminDurationMs
has no effect whatsoever either. - The LongPress gesture is cancelled after a little movement, whereas the iOS gesture doesn’t. I fixed this by explicitly setting
shouldCancelWhenOutside
andminDist
.
Here’s the relevant code to my items. As said, at runtime, they are rendered as children of a ScrollView parent component:
const [isLongPress, setLongPress] = useState(false);
const [offset, setOffset] = useState([-100, 100]);
const onLongPressGestureEvent = useAnimatedGestureHandler<LongPressGestureHandlerGestureEvent>({
onActive: (nativeEvent) => {
if(!isLongPress) {
runOnJS(setLongPress)(true);
runOnJS(setOffset)([-5, 5]);
}
},
onFinish: () => {
runOnJS(setLongPress)(false);
runOnJS(setOffset)([-100, 100]);
}
});
<Animated.View style={style}>
<PanGestureHandler
activeOffsetX={offset}
activeOffsetY={offset}
ref={panRef}
simultaneousHandlers={pressRef}
enabled={true}
onGestureEvent={onPanGestureEvent}>
<Animated.View style={StyleSheet.absoluteFill}>
<LongPressGestureHandler
shouldCancelWhenOutside={false}
maxDist={1000}
ref={pressRef}
simultaneousHandlers={panRef}
onGestureEvent={onLongPressGestureEvent}>
<Animated.View style={StyleSheet.absoluteFill}>
{children}
</Animated.View>
</LongPressGestureHandler>
</Animated.View>
</PanGestureHandler>
</Animated.View>
What’s happening
On Android, short flicks do properly scroll the ScrollView.
If I long-press and then start dragging, no scrolling happens (that’s good), but also no panning. While dragging my finger, I get continuous LongPress OnActive
events, but I get only on Pan OnStart
event but no other pan events (active or end).
On iOS, I get simultanous LongPress active / Pan active events, so I can animated the dragged item.
Package versions
- React Native: 0.63.4
- React Native Gesture Handler: 1.9.0
- Reanimated 2 RC 0
Issue Analytics
- State:
- Created 3 years ago
- Reactions:3
- Comments:8 (3 by maintainers)
Top GitHub Comments
some problem, IOS works fine, no luck on Android,
react: 17.0.1 => 17.0.1 react-native: 0.64.2 => 0.64.2 react-native-gesture-handler: 1.10.3 => 1.10.3
@NicholasBoccuzzi It has been released: https://github.com/software-mansion/react-native-gesture-handler/releases/tag/2.0.0