TL;DR
- On iOS
onStart and onEnd are both only called when the activation criteria is met (e.g. X [-5, 5])
- On Android
onStart is called before activation criteria is met, and onEnd is not, meaning anything that depends on an onEnd "cleanup" function won't work on Android.
Description
I'm having a horizontal image swiper implemented using a <PanGestureHandler> which does the following logic:
onStart: Cancels any animations on the translateX animation
onActive: Sets the translateX value to the gesture handler's state translation.x value
onEnd: Runs a spring animation on the translateX value to snap to an edge
I've set the activation criteria to the following:
<PanGestureHandler
ref={horizontalGestureHandler}
enabled={enableHorizontalSwipe}
onGestureEvent={onHorizontalGestureEvent}
activeOffsetX={HORIZONTAL_SWIPE_ACTIVE_X}
failOffsetY={HORIZONTAL_SWIPE_FAIL_Y}
maxPointers={1}>
Then I've added console.logs in onStart, onActive and onEnd.
When the user starts dragging with velocity and then releases the finger, you'd expect onEnd to take over and run the spring animation to snap to an edge. While this animation is running, the user can activate the gesture again to cancel the animation and start taking over swiping again.
When cancelling the onEnd with a gesture (i.e. dragging while the snap to edge spring animation is still playing), the user can also just tap the screen, which results in two different cases on the platforms:
- iOS: Nothing is called until the activation criteria is met, in my case [-5, 5] on X, so the animation continues to play until the user actually starts dragging instead of tapping
- Android:
onStart is called, even if the activation criteria isn't met yet (pointer hasn't moved [-5, 5] on X yet), and on release onEnd is not called, because activation criteria wasn't met! (Note: onFinish will be called, but I can't use that since then cross-handler interaction is weird)
In other words: on iOS everything works fine, but on Android onStart is called even before the activation criteria is met, causing the swiper to get stuck where it won't start the onEnd snap-to-edges spring animation.
Demo
What you're seeing is me spamming my left mouse button, the "finger" (my mouse) hasn't moved a single pixel in this demo, and should therefore not result in onStart being called since that requires the activation criteria of 5 pixel to the left or 5 pixel to the right.
Solutions
Only call onStart on Android if the activation criteria is actually met!
Package versions
- React: 16
- React Native: 0.63.3
- React Native Gesture Handler: 1.8.0
- React Native Reanimated: 2.0.0-alpha.8
TL;DR
onStartandonEndare both only called when the activation criteria is met (e.g. X[-5, 5])onStartis called before activation criteria is met, andonEndis not, meaning anything that depends on anonEnd"cleanup" function won't work on Android.Description
I'm having a horizontal image swiper implemented using a
<PanGestureHandler>which does the following logic:onStart: Cancels any animations on the translateX animationonActive: Sets the translateX value to the gesture handler's state translation.x valueonEnd: Runs a spring animation on the translateX value to snap to an edgeI've set the activation criteria to the following:
Then I've added
console.logs in onStart, onActive and onEnd.When the user starts dragging with velocity and then releases the finger, you'd expect
onEndto take over and run the spring animation to snap to an edge. While this animation is running, the user can activate the gesture again to cancel the animation and start taking over swiping again.When cancelling the
onEndwith a gesture (i.e. dragging while the snap to edge spring animation is still playing), the user can also just tap the screen, which results in two different cases on the platforms:onStartis called, even if the activation criteria isn't met yet (pointer hasn't moved [-5, 5] on X yet), and on releaseonEndis not called, because activation criteria wasn't met! (Note:onFinishwill be called, but I can't use that since then cross-handler interaction is weird)In other words: on iOS everything works fine, but on Android
onStartis called even before the activation criteria is met, causing the swiper to get stuck where it won't start theonEndsnap-to-edges spring animation.Demo
Solutions
Only call
onStarton Android if the activation criteria is actually met!Package versions