Skip to content

[Android] v3 gestures below a native ScrollView still activate after the ScrollView takes over the touch #4581

Closed

Description

@JacquesLeupin

Description

On Android, a v3 gesture whose GestureDetector sits inside a React Native ScrollView/FlatList row is not cancelled when the scroll view takes over the touch stream. A tap that turned into a scroll, or a tap that only stopped a fling, still activates when the finger lifts.

Expected: the tap is cancelled once the scroll view takes over. That's what happens with v2 Gesture.Tap() (the root cancels legacy handlers on the disallow request), with v3 buttons since #4441, and on iOS.

We hit this in production after migrating a swipeable list row from Gesture.Race(pan, tap) to useCompetingGestures(usePanGesture(...), useTapGesture(...)). Scrolling the list started opening the row the scroll began on, and tapping to stop a fling opened the row under the finger.

Cause, as far as I can tell from the sources:

Steps to reproduce

  1. Render the gist screen on Android. The List tab is a FlatList of rows, each with a v3 tap competing with a horizontal pan, and the header counts what fires.
  2. Put a finger on a row, drag to scroll, and lift within the tap's 500 ms. tap increments: 4 of 5 trials on an emulator.
    As a side effect, when the phantom tap activates on lift the root starts intercepting, so the list receives a cancel instead of the release and stops dead instead of flinging. Momentum after a drag showed up in 1 of 5 trials, against 5 of 5 once the tap is cancelled.
  3. Fling the list, then tap a row to stop it. tap increments: 5 of 5.
  4. For comparison, tapping a settled row and swiping a row sideways behave as expected.

Trials were driven with adb shell input swipe/input tap on main (a530859) in apps/expo-example.

A link to a Gist, an Expo Snack or a link to a repository based on this template that reproduces the bug.

https://gist.github.com/JacquesLeupin/0a30f72fcc02c82144f4b374e55d19a3

Gesture Handler version

3.3.0, and main (a530859)

React Native version

0.87.1 in our app; 0.86.2 in apps/expo-example

Platforms

Android

JavaScript runtime

Hermes

Workflow

React Native (without Expo) in our app; Expo dev client for the repro

Architecture

New Architecture (Fabric)

Build type

Release mode in our app; debug for the repro

Device

Real device and Android emulator

Device model

Pixel 9 (Android 17); Android 16 emulator (Pixel 9 Pro XL image)

Acknowledgements

Yes

Possible fix

Apply the #4441 rule to detector handlers in the same deferred sweep: cancel a non-active detector handler when the grab happens after DOWN, or when it happens on DOWN and the DOWN never reached its detector (a fling catch). Recording the last native DOWN in RNGestureHandlerDetectorView.dispatchTouchEvent is enough to tell those cases apart, and an eager disallow on DOWN that still lets the event through (the nested pager case from #2383) then cancels nothing. I have a PR ready and will link it here.

Activity

  1. m-bert commented on Oct 8, 2026

    @m-bert
    Collaborator

    Hi @JacquesLeupin! Thank you for reporting this issue.

    Correct me if I'm wrong, but this issue was already discussed in #4547. Can you try if using FlatList from Gesture Handler solves this problem?

  2. JacquesLeupin commented on Oct 8, 2026

    @JacquesLeupin
    ContributorAuthor

    Thanks @m-bert, appreciate you taking a look.

    I think this one's a little different from #4547. That was a Touchable inside Gesture Handler's own scroll views. This is GestureDetector gestures (taps, pans, ReanimatedSwipeable) inside React Native's ScrollView/FlatList, and it happens on a normal drag too, not just when stopping a fling.

    I did try Gesture Handler's FlatList. On main it works, but without #4548 (so on 3.3.0 today) a tap that stops a fling still fires. Swapping out every scroll container isn't really practical for us, and plenty of list libraries render React Native's ScrollView under the hood anyway. Since #4441 already made Touchable behave inside React Native's scroll views, #4582 brings detector gestures in line with that.

    Happy to rework it if you'd like a different approach.

  3. m-bert commented on Oct 9, 2026

    @m-bert
    Collaborator

    Hi @JacquesLeupin!

    I agree with you 😅 I did respond in the copilot review thread, please take a look.

  4. added a commit that references this issue on Oct 12, 2026
    0f8b2ba
  5. added a commit that references this issue on Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions