我正在研究如何在 React Native 中检测手指移动到视图中。例如,我在屏幕上有一个视图。我的手指按在视图之外,慢慢移向视图。当手指越过边界时,视图可以识别我的手指。
我研究了Gesture Responder和PanResponder。但我发现的所有例子都触及了观点并感动了它。
如果您有方法或示例代码来执行我上面所说的操作,请告诉我。
我需要做一些数学计算才能到达目的地吗?
提前谢谢您!
@LuongTrong 之前的评论谈到了这一点,但一旦您掌握了 PanResponder 的作用及其工作原理,它并不像听起来那么难。 您需要检测用户何时将手指拖动到视图上的方法是使用 PanResponder、view.onLayout 和视图引用。 当您想要跟踪的视图接触到加载和脱离加载时,捕获视图的 4 个角(onLayout 为您提供 x、y 和高度、宽度,因此需要进行一些添加)。使用 onPanResponderMove 方法,检查触摸点是否在视图的边界内,然后相应地更新 ref 的状态。
听起来比实际更复杂,这里有一个 App.js(100% 演示代码)演示了它是如何工作的。我已将“按钮”组件分解为一个单独的组件,以使其更可重用。
import React, {useEffect, useState} from 'react'
import {setStatusBarBackgroundColor, StatusBar} from 'expo-status-bar'
import {PanResponder, Pressable, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import {GestureHandlerRootView, PanGestureHandler} from 'react-native-gesture-handler'
import {useEvent} from 'react-native-reanimated'
const CustButton = React.forwardRef((props, ref) => {
const [viewLayout, setViewLayout] = useState({})
const selColor = 'red'
const unselectedColor = 'blue'
const [selectedColor, setSelectedColor] = useState(unselectedColor)
function getViewLatout() {
return viewLayout
}
const updateSelectionStatus = (isActive) => {
setSelectedColor(isActive ? selColor : unselectedColor)
}
const checkPoint = (x,y) => {
const {top, left, right, bottom} = viewLayout
return (x > left && x < right && y > top && y < bottom)
}
React.useImperativeHandle(ref, () => ({
// each key is connected to `ref` as a method name
// they can execute code directly, or call a local method
setActive: (isActive) => { updateSelectionStatus(isActive) },
isPointInView: (x,y) => { return checkPoint(x,y)}
}))
return (<View
ref={ref}
style={[styles.button, {backgroundColor: selectedColor}]}
onLayout={(evt) => {
const {x, y, height, width} = evt.nativeEvent.layout
const viewLayoutProp = {
top: y,
bottom: y + height,
right: x + width,
left: x
}
setViewLayout(viewLayoutProp)
}}>
<Text style={{color: 'white', fontSize: 24, fontWeight: 'bold'}}>move over me</Text>
</View>)
})
export default function App() {
const viewRef = React.useRef()
const viewRef2 = React.useRef()
const viewRef3 = React.useRef()
const checkIfAViewIsSelected = (evt) => {
const {pageX:x, pageY:y} = evt.nativeEvent
viewRef.current.setActive(viewRef.current.isPointInView(x,y))
viewRef2.current.setActive(viewRef2.current.isPointInView(x,y))
viewRef3.current.setActive(viewRef3.current.isPointInView(x,y))
}
const panResponder = React.useMemo(() =>
PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderTerminationRequest: (evt, gestureState) => true,
onPanResponderRelease: (evt, gestureState) => {
},
onPanResponderStart:(evt) => {
checkIfAViewIsSelected(evt)
},
onPanResponderMove: (evt, gestureState) => {
checkIfAViewIsSelected(evt)
}
}), [viewRef, viewRef2, viewRef3])
useEffect(() => {
if (viewRef.current == null) {
return;
}
}, [viewRef.current])
return (
<View style={styles.container}>
<View style={[styles.container, {backgroundColor: '#fff'}]}
{...panResponder.panHandlers}
>
<CustButton ref={viewRef} />
<CustButton ref={viewRef2} />
<CustButton ref={viewRef3} />
<StatusBar style="auto"/>
</View>
</View>
)
}
const styles = StyleSheet.create(
{
container: {
flex: 0,
backgroundColor: '#555',
alignItems: 'center',
justifyContent: 'center',
gap: 20,
height: '100%',
width:'100%'
},
button: {
flex: 0,
height: 100,
width: 250,
backgroundColor: 'red',
alignItems: 'center',
justifyContent: 'center'
}
})
真正的问题是:
希望这对您或偶然发现这篇文章的其他人有帮助。