From e68928dc1db8eb98880e65782d34e434bf5ff06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Tue, 21 Oct 2025 12:05:24 +0200 Subject: [PATCH 01/13] correctly attaching native gestures --- .../react/RNGestureHandlerDetectorView.kt | 19 ++++++++++++++++--- .../apple/RNGestureHandlerDetector.mm | 13 ++++++++++--- .../HostGestureDetector.web.tsx | 4 +++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt index f2f15d9711..a704b8ebf2 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt @@ -5,6 +5,7 @@ import android.view.View import com.facebook.react.bridge.ReadableArray import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.common.UIManagerType import com.facebook.react.uimanager.events.Event import com.facebook.react.views.view.ReactViewGroup import com.swmansion.gesturehandler.core.GestureHandler @@ -104,9 +105,17 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) { handlersToDetach.remove(tag) if (!attachedHandlers.contains(tag)) { if (shouldAttachGestureToChildView(tag)) { - // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that case we cannot - // attach `NativeViewGestureHandlers` here and we have to do it in `addView` method. - nativeHandlers.add(tag) + if (actionType == GestureHandler.ACTION_TYPE_LOGIC_DETECTOR) { + val child = (getViewByReactTag(viewTag) as? ReactViewGroup)?.getChildAt(0) + if (child != null) { + registry.attachHandlerToView(tag, child.id, GestureHandler.ACTION_TYPE_LOGIC_DETECTOR) + registry.getHandler(tag)?.hostDetectorView = this + } + } else { + // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that case we cannot + // attach `NativeViewGestureHandlers` here and we have to do it in `addView` method. + nativeHandlers.add(tag) + } } else { registry.attachHandlerToView(tag, viewTag, actionType) if (actionType == GestureHandler.ACTION_TYPE_LOGIC_DETECTOR) { @@ -183,4 +192,8 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) { }.filterNotNull() private fun ReadableArray.toIntList(): List = List(size()) { getInt(it) } + fun getViewByReactTag(reactTag: Int): View? { + val uiManager = UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC) + return uiManager?.resolveView(reactTag) + } } diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm index a0b6a53adf..6e28edc0f5 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm @@ -165,9 +165,16 @@ - (void)attachHandlers:(const std::vector &)handlerTags [handlersToDetach removeObject:@(tag)]; if (![attachedHandlers containsObject:@(tag)]) { if ([self shouldAttachGestureToSubview:@(tag)]) { - // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that - // case we cannot attach `NativeViewGestureHandlers` here and we have to do it in `didAddSubview` method. - [_nativeHandlers addObject:@(tag)]; + if (actionType == RNGestureHandlerActionTypeLogicDetector) { + [handlerManager attachGestureHandler:@(tag) + toViewWithTag:@([handlerManager viewForReactTag:@(viewTag)].subviews[0].tag) + withActionType:RNGestureHandlerActionTypeLogicDetector]; + [attachedHandlers addObject:@(tag)]; + } else { + // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that + // case we cannot attach `NativeViewGestureHandlers` here and we have to do it in `didAddSubview` method. + [_nativeHandlers addObject:@(tag)]; + } } else { if (actionType == RNGestureHandlerActionTypeLogicDetector) { [handlerManager attachGestureHandler:@(tag) toViewWithTag:@(viewTag) withActionType:actionType]; diff --git a/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx b/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx index 0ab4d714ae..048d523cfd 100644 --- a/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx +++ b/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx @@ -61,7 +61,9 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => { actionType, propsRef ); - attachedNativeHandlers.current.add(tag); + if (actionType !== ActionType.LOGIC_DETECTOR) { + attachedNativeHandlers.current.add(tag); + } } else { RNGestureHandlerModule.attachGestureHandler( tag, From 5fdc74ade5beb24906d8943c5e00ad7010f45c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Thu, 23 Oct 2025 11:45:33 +0200 Subject: [PATCH 02/13] simplify --- .../react/RNGestureHandlerDetectorView.kt | 16 ++++------------ .../apple/RNGestureHandlerDetector.mm | 15 ++++----------- .../NativeDetector/HostGestureDetector.web.tsx | 7 +++---- 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt index a704b8ebf2..a1e6b6c546 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt @@ -104,18 +104,10 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) { for (tag in newHandlers) { handlersToDetach.remove(tag) if (!attachedHandlers.contains(tag)) { - if (shouldAttachGestureToChildView(tag)) { - if (actionType == GestureHandler.ACTION_TYPE_LOGIC_DETECTOR) { - val child = (getViewByReactTag(viewTag) as? ReactViewGroup)?.getChildAt(0) - if (child != null) { - registry.attachHandlerToView(tag, child.id, GestureHandler.ACTION_TYPE_LOGIC_DETECTOR) - registry.getHandler(tag)?.hostDetectorView = this - } - } else { - // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that case we cannot - // attach `NativeViewGestureHandlers` here and we have to do it in `addView` method. - nativeHandlers.add(tag) - } + if (shouldAttachGestureToChildView(tag) && actionType != GestureHandler.ACTION_TYPE_LOGIC_DETECTOR) { + // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that case we cannot + // attach `NativeViewGestureHandlers` here and we have to do it in `addView` method. + nativeHandlers.add(tag) } else { registry.attachHandlerToView(tag, viewTag, actionType) if (actionType == GestureHandler.ACTION_TYPE_LOGIC_DETECTOR) { diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm index 6e28edc0f5..af6b8264f2 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm @@ -164,17 +164,10 @@ - (void)attachHandlers:(const std::vector &)handlerTags for (const int tag : handlerTags) { [handlersToDetach removeObject:@(tag)]; if (![attachedHandlers containsObject:@(tag)]) { - if ([self shouldAttachGestureToSubview:@(tag)]) { - if (actionType == RNGestureHandlerActionTypeLogicDetector) { - [handlerManager attachGestureHandler:@(tag) - toViewWithTag:@([handlerManager viewForReactTag:@(viewTag)].subviews[0].tag) - withActionType:RNGestureHandlerActionTypeLogicDetector]; - [attachedHandlers addObject:@(tag)]; - } else { - // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that - // case we cannot attach `NativeViewGestureHandlers` here and we have to do it in `didAddSubview` method. - [_nativeHandlers addObject:@(tag)]; - } + if ([self shouldAttachGestureToSubview:@(tag)] && actionType != RNGestureHandlerActionTypeLogicDetector) { + // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that + // case we cannot attach `NativeViewGestureHandlers` here and we have to do it in `didAddSubview` method. + [_nativeHandlers addObject:@(tag)]; } else { if (actionType == RNGestureHandlerActionTypeLogicDetector) { [handlerManager attachGestureHandler:@(tag) toViewWithTag:@(viewTag) withActionType:actionType]; diff --git a/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx b/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx index 048d523cfd..61d4f540ca 100644 --- a/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx +++ b/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx @@ -53,7 +53,8 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => { if ( RNGestureHandlerModule.getGestureHandlerNode( tag - ).shouldAttachGestureToChildView() + ).shouldAttachGestureToChildView() && + actionType !== ActionType.LOGIC_DETECTOR ) { RNGestureHandlerModule.attachGestureHandler( tag, @@ -61,9 +62,7 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => { actionType, propsRef ); - if (actionType !== ActionType.LOGIC_DETECTOR) { - attachedNativeHandlers.current.add(tag); - } + attachedNativeHandlers.current.add(tag); } else { RNGestureHandlerModule.attachGestureHandler( tag, From b8d999f5e06b164f45e5f57e4ba659c78418db9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Thu, 23 Oct 2025 12:32:03 +0200 Subject: [PATCH 03/13] fixed reattaching --- .../apple/RNGestureHandlerDetector.mm | 20 +++++---- .../src/v3/LogicDetector.tsx | 44 ++++++++++--------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm index af6b8264f2..5586b1b095 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm @@ -220,22 +220,24 @@ - (void)updateLogicChildren:(const std::vector( const [viewTag, setViewTag] = useState(-1); const logicMethods = useRef(props.gesture.detectorCallbacks); - const handleRef = useCallback((node: any) => { - viewRef.current = node; - if (!node) { - return; - } + const handleRef = useCallback( + (node: any) => { + viewRef.current = node; + if (!node) { + return; + } + let tag: number | null = null; + if (Platform.OS === 'web') { + tag = node; + } else { + tag = findNodeHandle(node); + } - if (Platform.OS === 'web') { - setViewTag(node); - } else { - const tag = findNodeHandle(node); if (tag != null) { + console.log('register ', tag); setViewTag(tag); } - } - }, []); + + return () => { + if (tag != null) { + console.log('unregister ', tag); + unregister(viewTag); + } + }; + }, + [props.children] + ); useEffect(() => { logicMethods.current = props.gesture.detectorCallbacks; }, [props.gesture.detectorCallbacks]); - useEffect(() => { - if (viewTag === -1) { - return; - } - - // Native Detector differentiates Logic Children through a viewTag, - // thus if viewTag changes we have to reregister - unregister(viewTag); - }, [viewTag]); - useEffect(() => { if (viewTag === -1) { return; From 359402e1e5618f80648e2c9417ac2a096364c3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Thu, 23 Oct 2025 12:41:37 +0200 Subject: [PATCH 04/13] fix ios detaching --- .../apple/RNGestureHandlerDetector.mm | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm index 5586b1b095..4599c79701 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm @@ -160,9 +160,17 @@ - (void)attachHandlers:(const std::vector &)handlerTags react_native_assert(handlerManager != nullptr && "Tried to access a non-existent handler manager") NSMutableSet *handlersToDetach = [attachedHandlers mutableCopy]; - for (const int tag : handlerTags) { [handlersToDetach removeObject:@(tag)]; + } + + for (const id tag : handlersToDetach) { + [handlerManager.registry detachHandlerWithTag:tag]; + [attachedHandlers removeObject:tag]; + [_nativeHandlers removeObject:tag]; + } + + for (const int tag : handlerTags) { if (![attachedHandlers containsObject:@(tag)]) { if ([self shouldAttachGestureToSubview:@(tag)] && actionType != RNGestureHandlerActionTypeLogicDetector) { // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that @@ -180,12 +188,6 @@ - (void)attachHandlers:(const std::vector &)handlerTags } } - for (const id tag : handlersToDetach) { - [handlerManager.registry detachHandlerWithTag:tag]; - [attachedHandlers removeObject:tag]; - [_nativeHandlers removeObject:tag]; - } - // This covers the case where `NativeViewGestureHandlers` are attached after child views were created. if (self.subviews[0]) { [self tryAttachNativeHandlersToChildView]; From 7d591f422d6e3a5a48a7b52eb4488224d1ce67b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Fri, 24 Oct 2025 19:05:15 +0200 Subject: [PATCH 05/13] removed unused method --- .../gesturehandler/react/RNGestureHandlerDetectorView.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt index a1e6b6c546..82230c2169 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt @@ -5,7 +5,6 @@ import android.view.View import com.facebook.react.bridge.ReadableArray import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.UIManagerHelper -import com.facebook.react.uimanager.common.UIManagerType import com.facebook.react.uimanager.events.Event import com.facebook.react.views.view.ReactViewGroup import com.swmansion.gesturehandler.core.GestureHandler @@ -184,8 +183,4 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) { }.filterNotNull() private fun ReadableArray.toIntList(): List = List(size()) { getInt(it) } - fun getViewByReactTag(reactTag: Int): View? { - val uiManager = UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC) - return uiManager?.resolveView(reactTag) - } } From d1eaf3c59003d6cda4b74445bb194b9877841e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Mon, 27 Oct 2025 14:19:46 +0100 Subject: [PATCH 06/13] removed console log that sneaked in --- packages/react-native-gesture-handler/src/v3/LogicDetector.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react-native-gesture-handler/src/v3/LogicDetector.tsx b/packages/react-native-gesture-handler/src/v3/LogicDetector.tsx index 69b2fd37fe..6ab480c0b9 100644 --- a/packages/react-native-gesture-handler/src/v3/LogicDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/LogicDetector.tsx @@ -28,13 +28,11 @@ export function LogicDetector( } if (tag != null) { - console.log('register ', tag); setViewTag(tag); } return () => { if (tag != null) { - console.log('unregister ', tag); unregister(viewTag); } }; From 91ea2e78e3983bdeb34a79d0030f63103de5743d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Mon, 27 Oct 2025 14:21:23 +0100 Subject: [PATCH 07/13] utilised ternary --- .../react-native-gesture-handler/src/v3/LogicDetector.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/react-native-gesture-handler/src/v3/LogicDetector.tsx b/packages/react-native-gesture-handler/src/v3/LogicDetector.tsx index 6ab480c0b9..7fc2e6ae60 100644 --- a/packages/react-native-gesture-handler/src/v3/LogicDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/LogicDetector.tsx @@ -20,12 +20,8 @@ export function LogicDetector( if (!node) { return; } - let tag: number | null = null; - if (Platform.OS === 'web') { - tag = node; - } else { - tag = findNodeHandle(node); - } + + const tag = Platform.OS === 'web' ? node : findNodeHandle(node); if (tag != null) { setViewTag(tag); From 3c2ddac0bb8ab8865c9a45ceda3df53872d39159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Mon, 27 Oct 2025 14:26:57 +0100 Subject: [PATCH 08/13] changed != to = --- .../gesturehandler/react/RNGestureHandlerDetectorView.kt | 2 +- .../apple/RNGestureHandlerDetector.mm | 2 +- .../src/v3/NativeDetector/HostGestureDetector.web.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt index 82230c2169..3425d8dbbc 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt @@ -103,7 +103,7 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) { for (tag in newHandlers) { handlersToDetach.remove(tag) if (!attachedHandlers.contains(tag)) { - if (shouldAttachGestureToChildView(tag) && actionType != GestureHandler.ACTION_TYPE_LOGIC_DETECTOR) { + if (shouldAttachGestureToChildView(tag) && actionType == GestureHandler.ACTION_TYPE_NATIVE_DETECTOR) { // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that case we cannot // attach `NativeViewGestureHandlers` here and we have to do it in `addView` method. nativeHandlers.add(tag) diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm index 4599c79701..db7d3c6794 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm @@ -172,7 +172,7 @@ - (void)attachHandlers:(const std::vector &)handlerTags for (const int tag : handlerTags) { if (![attachedHandlers containsObject:@(tag)]) { - if ([self shouldAttachGestureToSubview:@(tag)] && actionType != RNGestureHandlerActionTypeLogicDetector) { + if ([self shouldAttachGestureToSubview:@(tag)] && actionType == RNGestureHandlerActionTypeNativeDetector) { // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that // case we cannot attach `NativeViewGestureHandlers` here and we have to do it in `didAddSubview` method. [_nativeHandlers addObject:@(tag)]; diff --git a/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx b/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx index 61d4f540ca..cfb0b8290e 100644 --- a/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx +++ b/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx @@ -54,7 +54,7 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => { RNGestureHandlerModule.getGestureHandlerNode( tag ).shouldAttachGestureToChildView() && - actionType !== ActionType.LOGIC_DETECTOR + actionType === ActionType.NATIVE_DETECTOR ) { RNGestureHandlerModule.attachGestureHandler( tag, From 9eb434f17114b19d7865f4091c822777e693d4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Mon, 27 Oct 2025 15:06:01 +0100 Subject: [PATCH 09/13] only necessary changes --- .../apple/RNGestureHandlerDetector.mm | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm index db7d3c6794..5586b1b095 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm @@ -160,19 +160,11 @@ - (void)attachHandlers:(const std::vector &)handlerTags react_native_assert(handlerManager != nullptr && "Tried to access a non-existent handler manager") NSMutableSet *handlersToDetach = [attachedHandlers mutableCopy]; - for (const int tag : handlerTags) { - [handlersToDetach removeObject:@(tag)]; - } - - for (const id tag : handlersToDetach) { - [handlerManager.registry detachHandlerWithTag:tag]; - [attachedHandlers removeObject:tag]; - [_nativeHandlers removeObject:tag]; - } for (const int tag : handlerTags) { + [handlersToDetach removeObject:@(tag)]; if (![attachedHandlers containsObject:@(tag)]) { - if ([self shouldAttachGestureToSubview:@(tag)] && actionType == RNGestureHandlerActionTypeNativeDetector) { + if ([self shouldAttachGestureToSubview:@(tag)] && actionType != RNGestureHandlerActionTypeLogicDetector) { // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that // case we cannot attach `NativeViewGestureHandlers` here and we have to do it in `didAddSubview` method. [_nativeHandlers addObject:@(tag)]; @@ -188,6 +180,12 @@ - (void)attachHandlers:(const std::vector &)handlerTags } } + for (const id tag : handlersToDetach) { + [handlerManager.registry detachHandlerWithTag:tag]; + [attachedHandlers removeObject:tag]; + [_nativeHandlers removeObject:tag]; + } + // This covers the case where `NativeViewGestureHandlers` are attached after child views were created. if (self.subviews[0]) { [self tryAttachNativeHandlersToChildView]; From 8c42422b132935e22349e1b1edeba12227f26b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Mon, 27 Oct 2025 15:36:08 +0100 Subject: [PATCH 10/13] fix reattaching android --- .../react/RNGestureHandlerDetectorView.kt | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt index 3425d8dbbc..2738f04428 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt @@ -44,14 +44,25 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) { val logicChildrenToDetach = attachedLogicHandlers.keys.toMutableSet() val mappedChildren = newLogicChildren?.mapLogicChildren().orEmpty() + for (child in mappedChildren) { + logicChildrenToDetach.remove(child.viewTag) + } + + val registry = RNGestureHandlerModule.registries[moduleId] + ?: throw Exception("Tried to access a non-existent registry") + + for (child in logicChildrenToDetach) { + for (tag in attachedLogicHandlers[child]!!) { + registry.detachHandler(tag) + } + attachedLogicHandlers.remove(tag) + } for (child in mappedChildren) { if (!attachedLogicHandlers.containsKey(child.viewTag)) { attachedLogicHandlers[child.viewTag] = mutableSetOf() } - logicChildrenToDetach.remove(child.viewTag) - attachHandlers( child.handlerTags, child.viewTag, @@ -59,14 +70,6 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) { attachedLogicHandlers[child.viewTag]!!, ) } - - val registry = RNGestureHandlerModule.registries[moduleId] - ?: throw Exception("Tried to access a non-existent registry") - - for (tag in logicChildrenToDetach) { - registry.detachHandler(tag) - attachedLogicHandlers.remove(tag) - } } private fun shouldAttachGestureToChildView(tag: Int): Boolean { From 66e7f23cd7adf0f9ad8194dbdfe21ed51785cfd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Tue, 28 Oct 2025 08:28:39 +0100 Subject: [PATCH 11/13] preamptive fix on web --- .../v3/NativeDetector/HostGestureDetector.web.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx b/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx index cfb0b8290e..7938a52b0a 100644 --- a/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx +++ b/packages/react-native-gesture-handler/src/v3/NativeDetector/HostGestureDetector.web.tsx @@ -110,6 +110,14 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => { attachedLogicHandlers.current.keys() ); + props.logicChildren?.forEach((child) => { + logicChildrenToDetach.delete(child.viewTag); + }); + + logicChildrenToDetach.forEach((tag) => { + detachHandlers(EMPTY_HANDLERS, attachedLogicHandlers.current.get(tag)!); + }); + props.logicChildren?.forEach((child) => { if (!attachedLogicHandlers.current.has(child.viewTag)) { attachedLogicHandlers.current.set(child.viewTag, new Set()); @@ -130,10 +138,6 @@ const HostGestureDetector = (props: GestureHandlerDetectorProps) => { ActionType.LOGIC_DETECTOR ); }); - - logicChildrenToDetach.forEach((tag) => { - detachHandlers(EMPTY_HANDLERS, attachedLogicHandlers.current.get(tag)!); - }); }, [props.logicChildren]); return ( From ed852b69890b812dc3eec95330c9115e6dee8645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Thu, 30 Oct 2025 18:14:03 +0100 Subject: [PATCH 12/13] fixed naming --- .../apple/RNGestureHandlerDetector.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm index 5586b1b095..1a778dc25e 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm @@ -164,7 +164,7 @@ - (void)attachHandlers:(const std::vector &)handlerTags for (const int tag : handlerTags) { [handlersToDetach removeObject:@(tag)]; if (![attachedHandlers containsObject:@(tag)]) { - if ([self shouldAttachGestureToSubview:@(tag)] && actionType != RNGestureHandlerActionTypeLogicDetector) { + if ([self shouldAttachGestureToSubview:@(tag)] && actionType == RNGestureHandlerActionTypeNativeDetector) { // It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that // case we cannot attach `NativeViewGestureHandlers` here and we have to do it in `didAddSubview` method. [_nativeHandlers addObject:@(tag)]; From c06d53e2c84601ad2d7f402c4c8ce47aca262316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Antoni=20Kwa=C5=9Bniewski?= Date: Mon, 3 Nov 2025 12:33:10 +0100 Subject: [PATCH 13/13] detaching old tag --- .../src/v3/detectors/LogicDetector/LogicDetector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native-gesture-handler/src/v3/detectors/LogicDetector/LogicDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/LogicDetector/LogicDetector.tsx index 3d657f266d..72c4034618 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/LogicDetector/LogicDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/LogicDetector/LogicDetector.tsx @@ -44,7 +44,7 @@ export function LogicDetector( ? props.gesture.tags : [props.gesture.tag]; - unregister(viewTag, handlerTags); + unregister(tag, handlerTags); } }; },