Skip to content

Commit a39e03c

Browse files
akwasniewskij-piasecki
authored andcommitted
[android] fixed experimental pointers breaking after pan (#3801)
In a project using experimental pointer events, activation of the pan gesture stopped recognition of Js pointer events. This PR should resolve this issue. I believe the error is due to the fact that `onCancel` calls rootView.onChildStartedNativeGesture, which sets the `UNSET_CHILD_VIEW_ID` in JSPointerDispatcher.kt to current view tag, which is never cleared. This blocks pointer events from being called, as the pointer dispatcher thinks that some child is handling a native gesture. I added cleanup when all fingers have been lifted. Enable experimental pointer events: https://reactnative.dev/blog/2022/12/13/pointer-events-in-react-native#enable-feature-flags. Use the following code to test the component: <details> ```ts import React from 'react'; import { Text, Pressable, StyleSheet } from 'react-native'; import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler'; import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'; const END_POSITION = 200; function App(): React.JSX.Element { const [count, setCount] = React.useState(0); const [pressCount, setPressCount] = React.useState(0); const onLeft = useSharedValue(true); const position = useSharedValue(0); const panGesture = Gesture.Pan() .onUpdate((e) => { if (onLeft.value) { position.value = e.translationX; } else { position.value = END_POSITION + e.translationX; } }) .onEnd((e) => { if (position.value > END_POSITION / 2) { position.value = withTiming(END_POSITION, { duration: 100 }); onLeft.value = false; } else { position.value = withTiming(0, { duration: 100 }); onLeft.value = true; } }); const animatedStyle = useAnimatedStyle(() => ({ transform: [{ translateX: position.value }], })); return ( <GestureHandlerRootView style={styles.container}> <Pressable style={{ padding: 16, backgroundColor: '#aa0044' }} onPointerDown={() => setCount(n => n + 1)} onPressIn={() => setPressCount(n => n + 1)} > <Text style={{ color: 'black' }}>Press me</Text> </Pressable> <Text style={{ marginBottom: 16, color: 'black' }}> pointer: {count} -- press: {pressCount} </Text> <GestureDetector gesture={panGesture}> <Animated.View style={[styles.box, animatedStyle]} /> </GestureDetector> </GestureHandlerRootView> ); } const styles = StyleSheet.create({ container: { padding: 64, flex: 1, }, box: { height: 120, width: 120, backgroundColor: '#b58df1', borderRadius: 20, marginBottom: 30, }, }); export default App; ``` </details> If you have experimental pointer events turned on clicking on the upper pressable should increase both counters even after using pan gesture on the box below. Before this PR, after panning, only one counter worked.
1 parent 51c5a8c commit a39e03c

File tree

2 files changed

+11
-0
lines changed

2 files changed

+11
-0
lines changed

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import android.view.View
77
import android.view.ViewGroup
88
import android.widget.EditText
99
import com.facebook.react.uimanager.ReactCompoundView
10+
import com.facebook.react.uimanager.RootView
1011
import com.swmansion.gesturehandler.react.RNGestureHandlerRootHelper
1112
import com.swmansion.gesturehandler.react.RNGestureHandlerRootView
1213
import java.util.*
@@ -15,6 +16,7 @@ class GestureHandlerOrchestrator(
1516
private val wrapperView: ViewGroup,
1617
private val handlerRegistry: GestureHandlerRegistry,
1718
private val viewConfigHelper: ViewConfigurationHelper,
19+
private val rootView: ViewGroup,
1820
) {
1921
/**
2022
* Minimum alpha (value from 0 to 1) that should be set to a view so that it can be treated as a
@@ -57,6 +59,14 @@ class GestureHandlerOrchestrator(
5759
if (finishedHandlersCleanupScheduled && handlingChangeSemaphore == 0) {
5860
cleanupFinishedHandlers()
5961
}
62+
if (action == MotionEvent.ACTION_UP ||
63+
action == MotionEvent.ACTION_CANCEL ||
64+
action == MotionEvent.ACTION_HOVER_EXIT
65+
) {
66+
if (gestureHandlers.isEmpty() && rootView is RootView) {
67+
rootView.onChildEndedNativeGesture(rootView, event)
68+
}
69+
}
6070
return true
6171
}
6272

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
3838
wrappedView,
3939
registry,
4040
RNViewConfigurationHelper(),
41+
rootView,
4142
).apply {
4243
minimumAlphaForTraversal = MIN_ALPHA_FOR_TOUCH
4344
}

0 commit comments

Comments
 (0)