React Native中防止滑动过程中误触

news/2025/2/11 8:48:26/

React Native中防止滑动过程中误触

在使用React Native开发的时,当我们快速滑动应用的时候,可能会出现误触,导致我们会点击到页面中的某一些点击事件,误触导致页面元素响应从而进行其他操作,表现出非常不好的用户体验。

在这里插入图片描述

一、问题背景

常见的情形是长列表中,在滑动过程中可能会出现误触到列表中的某一项的情形,对于用户使用非常不好的体验。
如下列表组件中,就会存在滑动过程中产生误触的情况。

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组件可以更换为能够响应点击事件的任何组件,下面是官方列出的被引用到的组件,都能够使用这种方式处理误触。

     ButtonPanResponderPressableScrollViewTextTextInputTouchableHighlightTouchableOpacityTouchableNativeFeedbackTouchableWithoutFeedbackView
    

针对以上情况,能够将其应用到业务不同的误触情况下,下面是整理之后,完整的代码,根据以上情况可以再次进行组件封装,适配自己业务组件的调整。

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 (<TouchableOpacityonPressOut={(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>);
};

三、总结整理

  • 解决这次触摸,主要是使用点击事件本身的一个响应机制,在中间通过记录状态值的方式去处理
  • 使用到的方法涉及到按下时、抬起时、按下这三个过程
  • 通用功能组件需要进行封装,以达到业务功能上的适配

在这里插入图片描述


http://www.ppmy.cn/news/59043.html

相关文章

《程序员面试金典(第6版)》面试题 16.08. 整数的英语表示

题目描述 给定一个整数&#xff0c;打印该整数的英文描述。 示例 1: 输入: 123输出: “One Hundred Twenty Three” 示例 2: 输入: 12345输出: “Twelve Thousand Three Hundred Forty Five” 示例 3: 输入: 1234567输出: “One Million Two Hundred Thirty Four Thousand…

21安徽练习

题目分为4部分 APK 集群 流量 exe 我尽量都做一下&#xff0c;逆向不是很会&#xff0c;就当提升自己。 [填空题]请获取app安装包的SHA256校验值&#xff08;格式&#xff1a;不区分大小写&#xff09;&#xff08;10分&#xff09; e15095d49efdccb0ca9b2ee125e4d8136cac5…

前端三剑客React框架第一课入门的学习

前端三大框架React框架第一课入门的学习 前端三大框架的介绍 React:由facebook贡献&#xff0c;是一个基于javascript的前端库。它主要关注ui组件的构建&#xff0c;通过virtual dom等技术手段实现高效的渲染优化&#xff0c;可以与各种其他库和框架搭配使用&#xff0c;也有…

国产!全志科技T507-H工业核心板( 4核ARM Cortex-A5)规格书

1核心板简介 创龙科技 SOM-TLT507 是一款基于全志科技 T507-H 处理器设计的 4 核 ARM Cortex-A 53 全国产工业核心板,主频高达 1.416GHz 。核心板 CPU 、ROM 、RAM、电源、晶振等所有元器件均采用国产工业级方案,国产化率 100%。 核心板通过邮票孔连接方式引出 MIPI CSI 、…

SSL证书支持IP改成https地址

我们都知道SSL证书能为域名加密&#xff0c;那么IP地址可以实现https加密吗&#xff1f;答案当然是肯定的。为IP地址进行https加密不仅能保护IP服务器与客户端之间数据传输安全&#xff0c;还能对IP服务器进行身份验证&#xff0c;确保用户信息安全&#xff0c;增强用户对IP地址…

【文章学习系列之模型】Non-stationary Transformers

本章内容 文章概况总体结构主要模块Series Stationarization&#xff08;序列平稳化模块&#xff09;De-stationary Attention&#xff08;逆平稳化注意力模块&#xff09; 实验结果消融实验总结 文章概况 《Non-stationary Transformers:Exploring the Stationarity in Time …

Vue3.0

Vue3.0 动机与目的 更好的逻辑复用 与 代码组织 (composition组合式api) optionsAPI(旧) > compositionAPI&#xff08;新&#xff09;, 效果: 代码组织更方便了, 逻辑复用更方便了 非常利于维护!! 更好的类型推导 (typescript支持) **vue3 源码用 ts 重写了, vue3 对 ts 的…

什么是Java中的注解?

Java中的注解&#xff08;Annotation&#xff09;是一种元数据&#xff0c;用于为Java代码提供额外的信息和指示&#xff0c;例如代码的作用、编译时处理方式、运行时行为等等。注解可以通过在代码中添加注解元素来指定其属性值&#xff0c;从而对代码进行自定义和扩展。 Java…