如何在React Native开发中防止滑动过程中的误触
作者:suwu150
一、问题背景
常见的情形是长列表中,在滑动过程中可能会出现误触到列表中的某一项的情形,对于用户使用非常不好的体验。
如下列表组件中,就会存在滑动过程中产生误触的情况。
import React from 'react'; import { StyleSheet, Text, SafeAreaView, ScrollView, View, TouchableOpacity, StatusBar, } from 'react-native'; const App = () => { const list = Array.from(Array(100).keys()); const onPress = (e) => { alert(1); }; return ( <SafeAreaView style={styles.container}> <ScrollView style={styles.scrollView}> {list.map((item) => { return ( <TouchableOpacity onPress={onPress}> <View style={styles.containerView}> <Text style={styles.text}>{item}+ item</Text> </View> </TouchableOpacity> ); })} </ScrollView> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1, paddingTop: StatusBar.currentHeight }, scrollView: { marginHorizontal: 20 }, text: { fontSize: 1 }, containerView: { backgroundColor: 'pink', marginTop: 20, height: 50 }, }); export default App;
上面长列表,在滚动的过程中可能会出现误触的问题。
二、解决思路
我们应该如何处理这种情形,可以考虑从点击事件上入手,考虑根据距离的移动来进行组织是否响应点击事件
通过查看官方文档,我们能够发现点击时间在点击按下和抬起的过程中有一个过程回调,我们就可以利用这个回调进行处理误触了,有兴趣的小伙伴可以看看这块官方说明
由于点击事件执行过程原理
- onPressIn 在按压时被调用。
- onPressOut 在按压动作结束后被调用。
在按下 onPressIn 后,将会出现如下两种情况的一种:
用户移开手指,依次触发onPressOut 和onPress事件。
按压持续 500 毫秒以上,触发onLongPress 事件。(onPressOut 在移开手后依旧会触发。)
可以通过监听点击事件的方式来监听按钮点击,那我们来简单实现一个避免误触的方案
其中的核心原理就是点击事件的整个过程,总结来说就是下面的三个点击过程
onPressOut={(event) => { const [startX, startY] = [ event.nativeEvent.pageX, event.nativeEvent.pageY, ]; const currentTime = new Date().getTime(); const shouldReject = (Math.abs(pressInPointRef.current.startX - startX) > pointDistance || Math.abs(pressInPointRef.current.startY - startY) > pointDistance) && (currentTime - pressInTime.current) < pointMinTimeSpace; console.log('shouldReject', shouldReject); shouldReject && event?.preventDefault?.(); }} onPress={(event) => { if (event?.isDefaultPrevented?.()) return; onclick && onclick(); }} onPressIn={(event) => { pressInPointRef.current.startX = event.nativeEvent.pageX; pressInPointRef.current.startY = event.nativeEvent.pageY; pressInTime.current = new Date().getTime(); }}
当发生触摸时,通过onPressIn事件记录位置和获取事件戳,当指头触摸弹起时,通过onPressOut事件记录并且对比按下时的位置和按下时的时间,是否满足响应当前点击的条件,如果不满足响应,则使用event?.preventDefault?.()阻止其继续响应,最后根据onPress事件中if (event?.isDefaultPrevented?.()) return;判断该如何响应这次触摸点击,这就是整个过程。
pressInTime
调整按压时间区间,在按下时和抬起间隔小于该时间,则认为是误触,这个和距离区间(pointDistance)一起确定是否误触
pointDistance
调整按下和抬起时之间的距离,在按下时和抬起间隔小于该距离,则认为是误触,这个和按压时间(pressInTime)区间一起确定是否误触
调整显示组件
其中TouchableOpacity组件可以更换为能够响应点击事件的任何组件,下面是官方列出的被引用到的组件,都能够使用这种方式处理误触。
Button
PanResponder
Pressable
ScrollView
Text
TextInput
TouchableHighlight
TouchableOpacity
TouchableNativeFeedback
TouchableWithoutFeedback
View
针对以上情况,能够将其应用到业务不同的误触情况下,下面是整理之后,完整的代码,根据以上情况可以再次进行组件封装,适配自己业务组件的调整。
const App = () => { const list = Array.from(Array(100).keys()); const pressInPointRef = useRef({ startX: 0, startY: 0 }); const。pressInTime = useRef(0); const pointDistance = 100; const pointMinTimeSpace = 1000; const onclick = () => { console.log('按钮被点击...'); alert('按钮被点击...') }; return ( <SafeAreaView style={styles.container}> <ScrollView style={styles.scrollView}> {list.map((item) => { return ( <TouchableOpacity onPressOut={(event) => { const [startX, startY] = [ event.nativeEvent.pageX, event.nativeEvent.pageY, ]; const currentTime = new Date().getTime(); const shouldReject = (Math.abs(pressInPointRef.current.startX - startX) > pointDistance || Math.abs(pressInPointRef.current.startY - startY) > pointDistance) && (currentTime - pressInTime.current) < pointMinTimeSpace; console.log('shouldReject', shouldReject); shouldReject && event?.preventDefault?.(); }} onPress={(event) => { if (event?.isDefaultPrevented?.()) return; onclick && onclick(); }} onPressIn={(event) => { pressInPointRef.current.startX = event.nativeEvent.pageX; pressInPointRef.current.startY = event.nativeEvent.pageY; pressInTime.current = new Date().getTime(); }}> <View style={styles.containerView}> <Text style={styles.text}>{item}+ line</Text> </View> </TouchableOpacity> ); })} </ScrollView> </SafeAreaView> ); };
三、总结整理
- 解决这次触摸,主要是使用点击事件本身的一个响应机制,在中间通过记录状态值的方式去处理
- 使用到的方法涉及到按下时、抬起时、按下这三个过程
- 通用功能组件需要进行封装,以达到业务功能上的适配
到此这篇关于如何在React Native开发中防止滑动过程中的误触的文章就介绍到这了,更多相关React Native防止滑动误触内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!