Repository navigation
Conversation
…tach Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Summary
Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to
|
There was a problem hiding this comment.
🟢 Approval recommended
The focused lifecycle change preserves explicit cleanup, and no blocking issues remain.
No open issues 🎉
What changed in this PR
Fixes #4608 by preserving active Android detector gestures when Fabric briefly detaches and reattaches a view during a move.
Changes:
- Defers handler cleanup until the next main-looper message.
- Cancels pending cleanup on reattachment or explicit disposal.
- Adds a v3 drag-to-reorder reproduction screen.
| File | Description |
|---|---|
| packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt | Defers window-detach cleanup and cancels pending callbacks. |
| apps/common-app/src/new_api/tests/movedDetector/index.tsx | Adds a screen demonstrating gesture continuity during row moves. |
| apps/common-app/src/new_api/index.tsx | Registers the “Moved detector” test screen. |
Review effort: Balanced
|
Closing: as explained in #4608, this is expected in Gesture Handler 3, and |
Description
Fixes #4608
On Android, a gesture in a
GestureDetectoris cancelled when a re-render moves the detector's view while the gesture is active, e.g. a drag-to-reorder list moving the held row. Fabric moves a view by removing it and adding it back within one mount, so the detector is detached from the window only for that moment, butonDetachedFromWindowdetaches its handlers right away, and the registry cancels a handler whose view is set.This PR defers that detach to a main-looper message posted from
onDetachedFromWindow. The message detaches the handlers only if the view is still off the window when it runs.onAttachedToWindowremoves it, so a view moved within one mount keeps its handlers, and an active gesture carries on. A view that stays detached (hidden byActivity, or clipped) loses its handlers one message later than before. A view that's dropped is still detached at once byonDropViewInstance, anddetachAllHandlers()now also removes a pending message, so a recycled view never loses its new handlers to it.The change is Android only. iOS's detector also detaches in
willMoveToWindow:with a nil window; we haven't checked whether a move cancels a gesture there.It adds a "Moved detector" screen under Tests in the example app: grabbing a row moves it to the top while its pan is active.
Test plan
On the Android emulator (Pixel, Android 16, API 36), Release builds of
expo-example, each screen driven by Maestro, before this change and after it:onDeactivate, canceled: true35 ms afteronActivate; "cancelled"canceled: falseon release, 1.5 s later; "ended"FlatListrow dragged sideways, moved to the top<Activity>, hidden and shown again, then tappedWe also ran it in the app where we found it, a drag-to-reorder board, on the same build with and without the patch: its drag and section-drag flows failed without it and pass with it.
onAttachedToWindowcallsattachHandlers(handlersToAttach)again for a detector whose handlers were never detached. That's a no-op for them:attachHandlerssubscribes only tags it isn't subscribed to yet and detaches only tags no longer listed, soregistry.attachHandlerToView, and the cancel indetachHandlerInternal, never run for an attached handler. To check it on the device, we logged each attached handler's state (tag:state, 4 = ACTIVE, 5 = END) around the window hooks during a drag, in a temporary build:The pan stays ACTIVE through three moves of its detector, and the deferred detach never runs for it; it ends as END on release. A detector that stays off the window is still detached once the mount is done (40 ms later in the same log).
The Kotlin compiles in
basic-example,spotlessCheckpasses, andts-check, ESLint and Prettier pass for the new screen.🤖 Generated with Claude Code