Description
On Android, buttons rendered inside renderRightActions/renderLeftActions of ReanimatedSwipeable never fire onPress in 3.0.0. This affects every button implementation — RNGH Pressable, Touchable, RectButton are deterministically dead; core RN Pressable works only intermittently (it merely races the steal instead of losing outright). iOS is unaffected. This is likely the root cause behind many reports in #3223.
Root cause
ReanimatedSwipeable wraps the row content in a tap-to-close GestureDetector (enabled while the row is open). Three things combine:
- Since 3.0,
GestureDetector is a host component, and its native view frame is the bounding box of its children's layout frames (RNGestureHandlerDetectorShadowNode.cpp, layout()). The swipeable row moves aside via transform: translateX, which doesn't affect layout — so the tap detector's box stays full-row-sized and, while open, covers the revealed action buttons.
- On Android,
GestureHandlerOrchestrator.traverseWithPointerEvents has a special case in the BOX_NONE branch that records a detector view's own handlers even when no child is hit: if (found || view is RNGestureHandlerDetectorView) { recordViewHandlersForPointer(...) }. A press on a revealed button is inside the detector's (stale) bounds, so the tap-to-close handler starts tracking it.
- On finger-up, a button press is a perfect tap: the tap recognizes, activates first, runs close(), and its activation cancels the button's handler -
onPress never fires.
iOS is unaffected because of #3823 (the detector passes hit-testing through its own surface, so its recognizers never track touches over the buttons). v2 was unaffected because the legacy GestureDetector attached the tap directly to the row view, which is translated away and correctly excluded by the transform-aware hit test.
Expected: tapping a button in the revealed actions fires its onPress, as it does on iOS and as it did in 2.x.
Actual: on Android the press never fires - the tap-to-close gesture wins and the row closes instead.
Steps to reproduce
Reproduction
ReanimatedSwipeable + any button in renderRightActions, Android (new architecture):
<ReanimatedSwipeable
renderRightActions={() => (
<Touchable onPress={() => console.log('never logs on Android')}>
<Text>Delete</Text>
</Touchable>
)}
>
<View style={{ height: 64 }} />
</ReanimatedSwipeable>
Swipe open, tap the button -> on Android the tap-to-close gesture wins and the row closes instead; on iOS onPress fires.
Workaround (verified on device)
Shrink the tap-to-close gesture's active area to the visible part of the row with a negative hitSlop inside ReanimatedSwipeable:
const tapGestureHitSlop = useDerivedValue<HitSlop>(() =>
rowState.value === -1
? { right: -rightWidth.value }
: rowState.value === 1
? { left: -leftWidth.value }
: {}
);
const tapGesture = useTapGesture({
shouldCancelWhenOutside: true,
enabled: shouldEnableTap,
hitSlop: tapGestureHitSlop as unknown as HitSlop,
...
});
I know it's not a best solution, but it works (at least in my case)
A link to a Gist, an Expo Snack or a link to a repository based on this template that reproduces the bug.
https://github.com/priemskiyyy/rngh-v3-swipeable-android-repro
Gesture Handler version
3.0.0
React Native version
0.85.3
Platforms
Android
JavaScript runtime
Hermes
Workflow
Using Expo Prebuild or an Expo development build
Architecture
New Architecture (Fabric)
Build type
Debug mode
Device
Real device
Device model
Samsung Galaxy A14
Acknowledgements
Yes
Description
On Android, buttons rendered inside renderRightActions/renderLeftActions of ReanimatedSwipeable never fire onPress in 3.0.0. This affects every button implementation — RNGH Pressable, Touchable, RectButton are deterministically dead; core RN Pressable works only intermittently (it merely races the steal instead of losing outright). iOS is unaffected. This is likely the root cause behind many reports in #3223.
Root cause
ReanimatedSwipeablewraps the row content in a tap-to-closeGestureDetector(enabled while the row is open). Three things combine:GestureDetectoris a host component, and its native view frame is the bounding box of its children's layout frames (RNGestureHandlerDetectorShadowNode.cpp, layout()). The swipeable row moves aside viatransform: translateX, which doesn't affect layout — so the tap detector's box stays full-row-sized and, while open, covers the revealed action buttons.GestureHandlerOrchestrator.traverseWithPointerEventshas a special case in theBOX_NONEbranch that records a detector view's own handlers even when no child is hit:if (found || view is RNGestureHandlerDetectorView) { recordViewHandlersForPointer(...) }. A press on a revealed button is inside the detector's (stale) bounds, so the tap-to-close handler starts tracking it.onPressnever fires.iOS is unaffected because of #3823 (the detector passes hit-testing through its own surface, so its recognizers never track touches over the buttons). v2 was unaffected because the legacy
GestureDetectorattached the tap directly to the row view, which is translated away and correctly excluded by the transform-aware hit test.Expected: tapping a button in the revealed actions fires its onPress, as it does on iOS and as it did in 2.x.
Actual: on Android the press never fires - the tap-to-close gesture wins and the row closes instead.
Steps to reproduce
Reproduction
ReanimatedSwipeable+ any button inrenderRightActions, Android (new architecture):Swipe open, tap the button -> on Android the tap-to-close gesture wins and the row closes instead; on iOS onPress fires.
Workaround (verified on device)
Shrink the tap-to-close gesture's active area to the visible part of the row with a negative
hitSlopinsideReanimatedSwipeable:I know it's not a best solution, but it works (at least in my case)
A link to a Gist, an Expo Snack or a link to a repository based on this template that reproduces the bug.
https://github.com/priemskiyyy/rngh-v3-swipeable-android-repro
Gesture Handler version
3.0.0
React Native version
0.85.3
Platforms
Android
JavaScript runtime
Hermes
Workflow
Using Expo Prebuild or an Expo development build
Architecture
New Architecture (Fabric)
Build type
Debug mode
Device
Real device
Device model
Samsung Galaxy A14
Acknowledgements
Yes