React Native PanResponder onStartShouldSetPanResponder locationX 因平台而异
React Native PanResponder onStartShouldSetPanResponder locationX varies by platform
我是 RN 手势 apis 的新手,所以如果其中任何一个看起来像是根本不正确的方法,我将非常感谢您的反馈以及关于在哪里查看的任何建议。谢谢!
目标
- 使用 PanResponder api 仅处理点击和滑动手势
- 使用
onStartShouldSetPanResponder
仅处理点击和移动前滑动
- 保证由
onStartShouldSetPanResponder
处理的event.nativeEvent
具有相对于ListComponent的定位信息,而不是列表组件的子组件。
根据我是否通过 expo 的本地 Web 服务器和 expo ios 应用程序进行测试,以下代码会收到不同的 event.nativeEvent
。这似乎是合理的,因为底层基础设施有多么不同。
我的直觉是,在 ios,onStartShouldSetPanResponder 处理程序正在触发 'too late'(或为时过早?),也就是说,手势被归因于子组件,因此事件冒泡up to this handler 相对于子组件的定位,而不是下面渲染函数中的列表组件。
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>
)
鉴于列表组件为 300px 宽,并且列表组件中有 3 个 100px 宽的项目,从列表组件左侧点击宽度的大约 5/6 会产生 locationX ~250/300 (正确)在网络上,在 ios.
上为 50/300
List [----------------300px----------------]
Children [---100px---][---100px---][---100px---]
Tapping Here ---------------------------^^
似乎在 ios 上,事件是相对于第 3 个 100px 宽的子元素定位的。
其他上下文:
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"
},
最终设置了 ref onLayout
并忽略了 event.nativeEvent
以支持 gestureState.x0
和 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
我是 RN 手势 apis 的新手,所以如果其中任何一个看起来像是根本不正确的方法,我将非常感谢您的反馈以及关于在哪里查看的任何建议。谢谢!
目标
- 使用 PanResponder api 仅处理点击和滑动手势
- 使用
onStartShouldSetPanResponder
仅处理点击和移动前滑动 - 保证由
onStartShouldSetPanResponder
处理的event.nativeEvent
具有相对于ListComponent的定位信息,而不是列表组件的子组件。
根据我是否通过 expo 的本地 Web 服务器和 expo ios 应用程序进行测试,以下代码会收到不同的 event.nativeEvent
。这似乎是合理的,因为底层基础设施有多么不同。
我的直觉是,在 ios,onStartShouldSetPanResponder 处理程序正在触发 'too late'(或为时过早?),也就是说,手势被归因于子组件,因此事件冒泡up to this handler 相对于子组件的定位,而不是下面渲染函数中的列表组件。
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>
)
鉴于列表组件为 300px 宽,并且列表组件中有 3 个 100px 宽的项目,从列表组件左侧点击宽度的大约 5/6 会产生 locationX ~250/300 (正确)在网络上,在 ios.
上为 50/300List [----------------300px----------------]
Children [---100px---][---100px---][---100px---]
Tapping Here ---------------------------^^
似乎在 ios 上,事件是相对于第 3 个 100px 宽的子元素定位的。
其他上下文:
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"
},
最终设置了 ref onLayout
并忽略了 event.nativeEvent
以支持 gestureState.x0
和 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