Skip to content

onStart called before activation criteria is met #1225

@mrousavy

Description

@mrousavy

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:

  1. onStart: Cancels any animations on the translateX animation
  2. onActive: Sets the translateX value to the gesture handler's state translation.x value
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: Gesture handlersThis issue is related to problems with gesture handlersPlatform: AndroidThis issue is specific to Android

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions