react-native(RN)实现可拖动的悬浮按钮

news2025/1/13 2:38:03

一、PanResponder相关知识点

PanResponder类可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以用于识别简单的多点触摸手势。

默认情况下PanResponder会通过InteractionManager来阻止长时间运行的 JS 事件打断当前的手势活动。

它提供了一个对触摸响应系统响应器的可预测的包装。对于每一个处理函数,它在原生事件之外提供了一个新的gestureState对象:

onPanResponderMove: (event, gestureState) => {}

原生事件是指由以下字段组成的合成触摸事件:

nativeEvent

changedTouches - 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
identifier - 触摸点的 ID
locationX - 触摸点相对于父元素的横坐标
locationY - 触摸点相对于父元素的纵坐标
pageX - 触摸点相对于根元素的横坐标
pageY - 触摸点相对于根元素的纵坐标
target - 触摸点所在的元素 ID
timestamp - 触摸事件的时间戳,可用于移动速度的计算
touches - 当前屏幕上的所有触摸点的集合

一个gestureState对象有如下的字段:

stateID - 触摸状态的 ID。在屏幕上有至少一个触摸点的情况下,这个 ID 会一直有效。
moveX - 最近一次移动时的屏幕横坐标
moveY - 最近一次移动时的屏幕纵坐标
x0 - 当响应器产生时的屏幕坐标
y0 - 当响应器产生时的屏幕坐标
dx - 从触摸操作开始时的累计横向路程
dy - 从触摸操作开始时的累计纵向路程
vx - 当前的横向移动速度
vy - 当前的纵向移动速度
numberActiveTouches - 当前在屏幕上的有效触摸点的数量

基本用法

  componentWillMount: function() {
    this._panResponder = PanResponder.create({
      // 要求成为响应者:
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

      onPanResponderGrant: (evt, gestureState) => {
        // 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!

        // gestureState.{x,y} 现在会被设置为0
      },
      onPanResponderMove: (evt, gestureState) => {
        // 最近一次的移动距离为gestureState.move{X,Y}

        // 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}
      },
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderRelease: (evt, gestureState) => {
        // 用户放开了所有的触摸点,且此时视图已经成为了响应者。
        // 一般来说这意味着一个手势操作已经成功完成。
      },
      onPanResponderTerminate: (evt, gestureState) => {
        // 另一个组件已经成为了新的响应者,所以当前手势将被取消。
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
        // 默认返回true。目前暂时只支持android。
        return true;
      },
    });
  },

  render: function() {
    return (
      <View {...this._panResponder.panHandlers} />
    );
  },

二、实现方式

① 官网Demo

链接 ===> https://reactnative.cn/docs/next/panresponder
结合Animated和PanResponder实现,效果如下:

在这里插入图片描述

② PanResponder实现Demo

在这里插入图片描述
代码如下

// dx 和 dy:从触摸操作开始到现在的累积横向/纵向路程
//
// moveX 和 moveY:最近一次移动时的屏幕横/纵坐标
//
// numberActiveTouches:当前在屏幕上的有效触摸点的数量
//
// stated:和之前一样,用来识别手指的ID
//
// vx 和 vy:当前横向/纵向移动的速度
//
// x0 和 y0:当触摸操作开始时组件相对于屏幕的横/纵坐标

import React, {PureComponent, Component} from 'react';
import {
    StyleSheet,
    View,
    PanResponder,
} from 'react-native';


export default class TouchStartAndRelease extends PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            backgroundColor: 'red',
            marginTop: 100,
            marginLeft: 100,
        };
        this.lastX = this.state.marginLeft;
        this.lastY = this.state.marginTop;
    }

    componentWillMount() {
        this._panResponder = PanResponder.create({
            onStartShouldSetPanResponder: (evt, gestureState) => {
                return true;
            },
            onMoveShouldSetPanResponder: (evt, gestureState) => {
                return true;
            },
            onPanResponderGrant: (evt, gestureState) => {
                this._highlight();
            },
            onPanResponderMove: (evt, gestureState) => {
                console.log(`gestureState.dx : ${gestureState.dx}   gestureState.dy : ${gestureState.dy}`);
                this.setState({
                    marginLeft: this.lastX + gestureState.dx,
                    marginTop: this.lastY + gestureState.dy,
                });
            },
            onPanResponderRelease: (evt, gestureState) => {
                this._unhighlight();
                this.lastX = this.state.marginLeft;
                this.lastY = this.state.marginTop;
            },
            onPanResponderTerminate: (evt, gestureState) => {
            },
        });
    }

    _unhighlight() {
        this.setState({
            backgroundColor: 'red',
        });
    }

    _highlight() {
        this.setState({
            backgroundColor: 'blue',
        });
    }

    render() {
        return (
            <View style={styles.container}>
                <View style={[styles.redView,
                    {
                        backgroundColor: this.state.backgroundColor,
                        marginTop: this.state.marginTop,
                        marginLeft: this.state.marginLeft,
                    }
                ]}
                      {...this._panResponder.panHandlers}
                />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    redView: {
        width: 100,
        height: 100,
    }
});

三、拓展

手势移动与点击事件冲突解决办法

参考 react-native 手势移动与点击事件冲突解决办法

代码如下

        this._panResponder = PanResponder.create({

            onPanResponderGrant: (evt, gestureState) => {
                //触摸开始
                this.DragMove = false;
            },

            onPanResponderMove: (evt, gestureState) => {
                /*
                moveX - 最近一次移动时的屏幕横坐标
                moveY - 最近一次移动时的屏幕纵坐标
                x0 - 当响应器产生时的屏幕坐标
                y0 - 当响应器产生时的屏幕坐标
                dx - 从触摸操作开始时的累计横向路程
                dy - 从触摸操作开始时的累计纵向路程
                vx - 当前的横向移动速度
                vy - 当前的纵向移动速度
                */
                if (gestureState.dx !== 0 || gestureState.dy !== 0) {
                    this.DragMove = true;
                }
            },
            onPanResponderRelease: (evt, gestureState) => {
                //触摸释放
                
                if(this.DragMove){//拖动
                    this.lastX = this.state.DragMarginLeft;
                    this.lastY = this.state.DragMarginTop;
                }else{//点击
                    console.log("onPanResponderRelease OnClick")
                }
            },
        });

四、参考

  • rn实现一个view的拖拽
  • react-native 手势移动与点击事件冲突解决办法
  • RN-可拖动的悬浮按钮 动画+手势Android点击的时候会坐标跳变,我采用第一种方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/917365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JFrog Artifactory介绍

JFrog Artifactory 1. 简介2. 安装3. 使用说明3.1 界面展示3.2 仓库搭建流程&#xff08;本地库&#xff09;3.3 普通用户界面展示3.4 上传制品&#xff0c;可单传或多传3.5 下载制品3.6 支持搜索3.7 单个制品复制移动删除3.8 用户管理3.9 存储信息3.10 基本设置 4. 前期调研被…

如何使用Java可观察性进行有效编码

无论您是经验丰富的开发人员、还是数据库管理员、亦或NoSQL数据库的爱好者&#xff0c;可能已经注意到&#xff0c;在如今快速发展的企业架构格局中&#xff0c;MongoDB和Couchbase已成为NoSQL数据库的两大典型竞品。 本文将通过展示在真实企业架构中使用MongoDB和Couchbase的…

SpringCloud教程 | 第四篇:断路器(Hystrix)

在微服务架构中&#xff0c;根据业务来拆分成一个个的服务&#xff0c;服务与服务之间可以相互调用&#xff08;RPC&#xff09;&#xff0c;在Spring Cloud可以用RestTemplateRibbon和Feign来调用。为了保证其高可用&#xff0c;单个服务通常会集群部署。由于网络原因或者自身…

07-Vue基础之综合案例——小黑记事本

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

高斯分布(正态分布)详解

高斯分布 一、概念二、详解和例子说明三、判断数据是否服从高斯分布四、高斯分布实际应用 一、概念 定义&#xff1a;随机变量X服从一个数学期望 μ \mu μ、方差为 σ \sigma σ的高斯分布&#xff0c;又名正态分布。当μ 0,σ 1时的正态分布是标准正态分布。 高斯分布概率…

使用Matlab coder 生成函数‘referencePathFrenet’ 对应C/C++代码含有超大数组

嵌入式需要使用C/C集成&#xff0c;开发使用Matlab&#xff0c;然后使用 coder 生成函数‘referencePathFrenet’ 生成了对应的C/C代码&#xff0c;然而C代码含有大量超大数组导致嵌入式无法集成&#xff1a; 分析Matlab 源代码发现是dclothoid.m 里面路径插值的时候默认使用了…

制作一个专属于安防监控业的小程序商城

随着科技的发展和人们生活水平的提高&#xff0c;安防监控设备在我们的日常生活中起到了越来越重要的作用。因此&#xff0c;建立一个安防监控设备商城小程序就变得尤为重要。下面将介绍如何建立这样一个小程序。 第一步&#xff0c;登录乔拓云平台后台&#xff0c;进入商城管理…

奇怪的没有文件或目录(Deepin+富瀚微)

最近在Linux下进行一些开发&#xff0c;遇到了问题。从UOS折腾到Deepin&#xff0c;最终在参考如下链接完成&#xff0c;非常感谢&#xff0c;记录下来&#xff0c;希望对后面的学习者有帮助。作者使用的可能是ubuntu&#xff0c;我使用的是deepin。我安装的是富瀚微的工具链。…

【Linux】【驱动】第一个相对完整的驱动编写

【Linux】【驱动】第一个相对完整的驱动编写 续1.驱动部分的代码2 app 代码3 操作相关的代码 续 这个章节会讲述去直接控制一个GPIO&#xff0c;高低电平。 因为linux不允许直接去操作寄存器&#xff0c;所以在操作寄存器的时候就需要使用到函数&#xff1a;ioremap 和iounma…

RedisTemplate和StringRedisTemplate的区别、对比

学习 Jedis、RedisTemplate、StringRedisTemplate之间的比较 博客中提到&#xff1a;一. Jedis是Redis官方推荐的面向Java的操作Redis的客户端。 二. RedisTemplate,StringRedisTemplate是SpringDataRedis中对JedisApi的高度封装。SpringDataRedis相对于Jedis来说可以方便地更…

Qt+C++动力监控动画仿真SCADA上位机

程序示例精选 QtC动力监控动画仿真SCADA上位机 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<QtC动力监控动画仿真SCADA上位机>>编写代码&#xff0c;代码整洁&#xff0c;规则…

心理与神经生物工程交叉学科国际论坛—暨第17届复合医学工程国际会议(CME2023)

心理与神经生物工程交叉学科国际论坛—暨第17届复合医学工程国际会议&#xff08;CME2023&#xff09; International Forum on the Intersection of Psychology and Neuromedical Engineering -17th International Conference on Complex Medical Engineering (CME2023) 心…

字节跳动 从需求到上线全流程 软件工程流程 需求评估 MVP

走进后端开发流程 整个课程会带大家先从理论出发&#xff0c;思考为什么有流程 大家以后工作的团队可能不一样&#xff0c;那么不同的团队也会有不同的流程&#xff0c;这背后的逻辑是什么 然后会带大家按照走一遍从需求到上线的全流程&#xff0c;告诉大家在流程的每个阶段&am…

功率放大器在电子实验中的作用是什么

功率放大器在电子实验中扮演着重要的角色&#xff0c;它具有多种作用和应用。在本文中&#xff0c;我们将详细介绍功率放大器在电子实验中的作用。 信号放大&#xff1a;功率放大器能够将输入信号的功率放大到更高的水平。在电子实验中&#xff0c;信号放大是非常常见的需求。通…

冒险岛 vcruntime140.dll 丢失问题的多种方法,几种解决方法都有效

当您尝试启动冒险岛游戏时&#xff0c;可能会遇到一个名为“vcruntime140.dll 丢失”的错误提示。vcruntime140.dll 是冒险岛游戏所需的一个重要系统文件&#xff0c;如果系统无法找到或加载该文件&#xff0c;您将无法正常启动游戏。在本文中&#xff0c;我们将详细介绍解决冒…

用友T3T6登录报错检测公共组件softcop.dll时未能通过,公共组件可能被破坏。

导致原因&#xff0c;windows 10操作系统&#xff0c;预制验证证书更新故障。 操作系统原因导致的。大量客户报错。 临时解决方法&#xff1a;把电脑系统日期改为 2023-08-01日以前。 根治解决方法&#xff0c;重置windows 预制证书&#xff0c;刷新签名证书。

【C++/C 实现球球大作战】

目录 1.引言2.游戏设计&#xff1a;概述游戏的玩法和操作方式。3.游戏实现&#xff08;1&#xff09;函数 GameInit() 初始化游戏的函数。&#xff08;2&#xff09;函数 GameDraw() 用于绘制游戏场景的函数。&#xff08;3&#xff09;函数 keyControl(int speed) 负责处理键盘…

新能源汽车技术的最新进展和未来趋势

文章目录 电池技术的进步智能驾驶与自动驾驶技术充电基础设施建设新能源汽车共享和智能交通未来趋势展望结论 &#x1f389;欢迎来到AIGC人工智能专栏~探索新能源汽车技术的最新进展和未来趋势 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客…

请注意:名字里千万不要有凶数

人与人之间相处&#xff0c;最重要的就是信任二字。 而被人相信和被人欣赏一样&#xff0c;都是值得我们喜乐和感动的事情。 曾经&#xff0c;峰民在常德工作室接待一位预约福主&#xff0c; 这位福主一见面就给了峰民一个感恩红包&#xff0c;峰民非常感动。 这位福主是非常的…

RISC-V公测平台发布 · 在SG2042上配置Jupiter+Octave科学计算环境

简介 JupyterHub是一个开源的共享计算平台&#xff0c;它为每个用户管理一个单独的 Jupyter 环境&#xff0c; 可以用于学生班级、企业数据科学小组或科学研究小组。它是一个多用户中心&#xff0c;可以生成、管理和代理多个单用户Jupyter笔记本服务器的实例。 GNU Octave是一…