I'm new to RN gesture apis, so if any of this looks like a fundamentally incorrect approach, I would really appreciate the feedback as well as any suggestions on where to look instead. Thanks! 🙏
Goals
onStartShouldSetPanResponder
to handle tap only and pre-move swipeevent.nativeEvent
handled by onStartShouldSetPanResponder
has positioning information relative to the ListComponent, not a child of the list component.The following code receives a different event.nativeEvent
according to whether I am testing via expo's local web server and expo ios app. This seems reasonable, given how different the underlying infrastructures are.
My hunch is that on ios, the onStartShouldSetPanResponder handler is firing 'too late' (or too early?), that is, the gesture is being attributed to a child component, so the event bubbling up to this handler has positioning relative to the child component, not the list component in the render function below.
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: (event: GestureResponderEvent) => {
console.log(event.nativeEvent.locationX)
updateSelectionValue(event.nativeEvent.locationX) // does some math and conditionally updates local state
},
onStartShouldSetPanResponder: () => true,
onPanResponderMove: handleSwipe,
})
).current
return (
<View onLayout={handleLayout} {...panResponder.panHandlers}>
<ListComponent proportion={selectionValue} {...props} />
</View>
)
Given that the list component is 300px wide, and there are 3 100px wide items in the list component, tapping approximately 5/6 of the width from left side of the list component yields a locationX of ~250/300 (correct) on web and 50/300 on ios.
List [----------------300px----------------]
Children [---100px---][---100px---][---100px---]
Tapping Here ---------------------------^^
It seems that on ios, the event is positioned relative to the 3rd 100px wide child element.
Additional Context:
node --version
v15.12.0
"dependencies": {
"expo": "~40.0.0",
"expo-status-bar": "~1.0.3",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
"react-native-web": "~0.13.12"
},
ended up setting a ref onLayout
and ignoring event.nativeEvent
in favor of gestureState.x0
and gestureState.moveX
let coords = useRef({ x: -1, y: -1 }).current
const handleLayout = useCallback((event: LayoutChangeEvent) => {
const { x, y } = event.nativeEvent.layout
coords = { x: Math.round(x), y: Math.round(y) }
}, [])
...
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderStart: (event, gestureState) =>
updateSelectionValue(gestureState.x0 - coords.x),
onPanResponderMove: (event, gestureState) =>
updateSelectionValue(gestureState.moveX - coords.x),
})
).current