在rngh(react-native-gesture-handler) 是rn一个常用的原生手势库,其手势响应运行在原生层,相比rn原生的具备更高性能与更快响应,本文主要记录其与手势与事件冲突问题 个人使用的是rngh v2版本
本文解决的是嵌套在GestureDetector内部想要触发事件的问题。
1.普通按钮与手势冲突
js
function(){
return
<>
<GestureDetector>
//其他组件
//按钮部分 <Button/>..
//其他组件
</GestureDetector>
</>
}
以上代码结构是常规的按钮被GestureDetector包裹,在这块只会触发rngh的手势,无法触发按钮事件
使用Pressable组件
该组件是rngh导出的组件,使用的是原生层级的响应,可以与GestureDetector包裹配置的手势同时触发,需要设置变量去拦截手势触发的逻辑,不推荐
嵌套GestureDetector
js
const playButtonGesture = Gesture.Tap().runOnJS(true);
const onceTap = Gesture.Tap()
.requireExternalGestureToFail(playButtonGesture)
.maxDuration(350)
.onStart(() => {
console.log("点击");
});
<GestureDetector gesture={Gesture.Race(onceTap)}>
<View>
//其他组件
<GestureDetector gesture={playButtonGesture}>
<View>
//按钮部分
</View>
</GestureDetector>
//其他组件
</View>
</GestureDetector>
</>
通过嵌套GestureDetector给内部设置单独的手势并且使用requireExternalGestureToFail在外层排除内部手势,这样就做到了对内部按钮单独的点击响应
2.组件事件与原生冲突
就以@react-native-community/slider为例
js
import Slider from "@react-native-community/slider";
import { useState } from "react";
import { View } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
function Test() {
const [currentTime, setCurrentTime] = useState(0);
// 为Slider创建专用手势
const sliderGesture = Gesture.Native();
return (
<>
//1.包裹在内部
<GestureDetector gesture={sliderGesture}>
<View>
<Slider
minimumTrackTintColor={"rgba(102, 51, 255, 1)"}
maximumTrackTintColor={"rgba(230, 230, 230, 1)"}
thumbTintColor={"rgba(102, 51, 255, 1)"}
minimumValue={0}
maximumValue={200}
value={currentTime}
onTouchStart={() => {
console.log("onTouchStart");
}}
onSlidingStart={(value) => {
console.log(value, "onSlidingStart");
}}
onValueChange={(val) => {
setCurrentTime(val);
console.log("onValueChange");
}}
onSlidingComplete={() => {
console.log("onSlidingComplete");
}}
/>
</View>
</GestureDetector>
//2.不包裹在内部没有问题
<Slider
minimumTrackTintColor={"rgba(102, 51, 255, 1)"}
maximumTrackTintColor={"rgba(230, 230, 230, 1)"}
thumbTintColor={"rgba(102, 51, 255, 1)"}
minimumValue={0}
maximumValue={200}
value={currentTime}
onTouchStart={() => {
console.log("onTouchStart");
}}
onSlidingStart={(value) => {
console.log(value, "onSlidingStart");
}}
onValueChange={(val) => {
setCurrentTime(val);
console.log("onValueChange");
}}
onSlidingComplete={() => {
console.log("onSlidingComplete");
}}
/>
</>
);
}
export default Test;
包裹在内部需要使用Gesture.Native();这样手势拦截后会把事件转移到Slider组件,这样就可以触发onSlidingComplete。
目前存在的问题就是Slider组件无法拖动,个人在寻找解决方案中,也寻找答案
当然,最能解决的方案就是不嵌套在GestureDetector内部!