RN仿微信朋友圈图片拖拽删除

2023-11-07

前言

之前负责的一个需求,让在RN端做仿微信朋友圈的图片删除和排序,由于经验和时间限制,就跟PM协商改为点击删除,由此欠下一个技术栈,今天是来还债的。本文基于transform实现,而非定位。

源码

初始时

将数据源转化为如下格式

const dataArray = props.dataArray.map((item, index)=>{
  const newData = {}
  const translateX = (index % COLUMN_NUM) * this.itemW;
  const translateY = parseInt((index/COLUMN_NUM)) * this.itemW;

  newData.data = item; // 原始内容
  newData.originIndex = index; // 初始下标
  newData.originX = translateX; // 当前项基于父试图的相对x值
  newData.originY = translateY; // 当前项基于父试图的相对y值
  // 当前项的偏移量,初始时都是按照正常的布局来,都不需要偏移,故都为0
  newData.transAnimated = new Animated.ValueXY({ 
    x: 0,
    y: 0,
  });
  return newData
});
this.setState({ dataArray });

渲染时

新数据源属性做如下分配

{this.state.dataArray.map((item, index) => (
  <Draggable 
    ref={ref => this.refDrag.set(index, ref)} // 收集每项的ref引用
    pan={this.state.dataArray[index].transAnimated} // 创建的动画给到每一项
    key={`${item.data}`} 
    destination={{ // 删除区域
      x: 0,
      y: ScreenH-40,
    }} 
    onMoveStart={() => this.handleMoveStart(item.originIndex)} // 此处不要使用map的index,因为排序后数组的数组没有变
    onMoveEnd={this.handleMoveEnd} 
    onMove={this.handleMove}
    onArriveDestination={() => this.handleArriveDestination(item.data)} 
  >
    {this.renderItem(item.data)}
  </Draggable>
))}

开始拖拽

将如下属性赋值给this.touchCurItem

handleMoveStart = (move) => {
  this.touchCurItem = {
  ref: this.refDrag.get(move), // 获取当前拖拽的item引用
  index: move, // 当前拖拽item的下标
  moveToIndex: 0, // 将要拖拽到的位置,初始为0即可
}

拖拽中

不断计算所有item(除拖拽项)将要到达的位置,然后用动画移动

handleMove = (e, gestureState) => {
  if (!this.touchCurItem) return;
  // 偏移量
  let translateX = gestureState.dx;
  let translateY = gestureState.dy;

  // 让拖拽项跟着手指移动
  this.state.dataArray[this.touchCurItem.index].transAnimated.setOffset({
    x: translateX,
    y: translateY
  });
    
  let moveXNum = translateX/this.itemW
  let moveYNum = translateY/this.itemH;

  // 向四个方向移动一半位置就触发排序
  if (moveXNum > 0) {
    moveXNum = parseInt(moveXNum+0.5)
  } else if (moveXNum < 0) {
    moveXNum = parseInt(moveXNum-0.5)
  }
  if (moveYNum > 0) {
    moveYNum = parseInt(moveYNum+0.5)
  } else if (moveYNum < 0) {
    moveYNum = parseInt(moveYNum-0.5)
  }

  let moveToIndex = this.touchCurItem.index + moveXNum + moveYNum * COLUMN_NUM;

  // 边缘线制
  if (moveToIndex > this.state.dataArray.length-1) {
    moveToIndex = this.state.dataArray.length-1
  } else if (moveToIndex < 0) {
    moveToIndex = 0;
  }

  if (this.touchCurItem.moveToIndex == moveToIndex ) return;

  this.touchCurItem.moveToIndex = moveToIndex
  this.state.dataArray.forEach((item,index)=> {
    let nextItem = null
    if (index > this.touchCurItem.index && index <= moveToIndex) { // 向右拖拽
      nextItem = this.state.dataArray[index-1]
    } else if (index >= moveToIndex && index < this.touchCurItem.index) { // 向左拖拽
      nextItem = this.state.dataArray[index+1]
    } else if (index != this.touchCurItem.index &&
          (item.transAnimated.x._value != item.originX || item.transAnimated.y._value != item.originY)) { // 处理不松开时左右滑动
      nextItem = this.state.dataArray[index]
    } 
    if (!nextItem) return;
    Animated.timing(
      item.transAnimated,
      {
        // 还记得在初始时的构造的数据源么,curItem和nextItem偏移量的差值就是当前想要到达的位置
        toValue: {x: parseInt(nextItem.originX+0.5 - item.originX),y: parseInt(nextItem.originY+0.5 - item.originY)},
        duration: 300,
        easing: Easing.out(Easing.quad),
        useNativeDriver: false,
      }
    ).start()
  })
}

拖拽结束

handleMoveEnd = () => {
  const curIndex = this.touchCurItem.index;
  const moveToIndex = this.touchCurItem.moveToIndex;
  const curItem = this.state.dataArray[this.touchCurItem.index];
  const moveToItem = this.state.dataArray[moveToIndex];

  let translateX = 0;
  let translateY = 0;
  
  // 判断移动是否达到移动标准,若是:动画方式返回原位置,否:动画偏移到新位置
  if (curIndex != moveToIndex) {
    translateX = parseInt(moveToItem.originX - curItem.originX+0.5);
    translateY = parseInt(moveToItem.originY - curItem.originY+0.5); 
  }
  Animated.timing(
    curItem.transAnimated,
    {
       toValue: {x: translateX,y: translateY},
       duration: 300,
       easing: Easing.out(Easing.quad),
       useNativeDriver: false,
    }
  ).start()
  this.touchCurItem = null;
  this.changePosition(curIndex, moveToIndex);
}

// 每次排序结束,按照新的排序整理dataArray
changePosition(startIndex,endIndex) {
  let isCommon = true; // 向右边移
  if (startIndex > endIndex) {  // 向左移
    isCommon = false 
    let tempIndex = startIndex
    startIndex = endIndex
    endIndex = tempIndex
  }

  const newDataArray = [...this.state.dataArray].map((item,index)=>{
    let newIndex = null;
    if (isCommon) {
      if (endIndex > index && index >= startIndex) {
        newIndex = index+1
      } else if (endIndex == index) {
        newIndex = startIndex
      }
    } else {
      if (endIndex >= index && index > startIndex) {
        newIndex = index-1
      } else if (startIndex == index) {
        newIndex = endIndex
      }
    }

    if (newIndex != null) {
      const newItem = {...this.state.dataArray[newIndex]}
      newItem.originX = item.originX
      newItem.originY = item.originY
      newItem.originIndex = item.originIndex;
      newItem.transAnimated = new Animated.ValueXY({ // 每次排序过后都将偏移量给清空,准备下次排序
        x: 0,
        y: 0,
      })
      item = newItem
    }
    return item
  })
    
  this.setState({
    dataArray: newDataArray
  });
}

拖拽删除

这个比较简单了,通过通知的方式来传送消息,没啥可说的,有兴趣直接看源码吧

参考链接

  1. react-native-drag-sort
  2. rndd
  3. RN动画详解
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RN仿微信朋友圈图片拖拽删除 的相关文章

  • CSS3中的3D旋转 rotate、3D位移 translate

    这里只考虑 chrome 的兼容 3DrotateDemo html lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8
  • Translate Aticle

    最近在Thinkpad上安装Ubuntu12 04的时候 xff0c 经历了几个问题 xff0c 发现BOIS里多了很多选项 xff0c 而且安装双系统也有UEFI有关 xff0c 在网站上找了一篇文章 xff0c 发现这还是一个新概念 x
  • Zotero 超好用插件的下载链接及配置方法(PDF-translate/ZotFile/茉莉花/Zotero Scihub)

    目录 前言插件安装方法插件一 xff1a 文献翻译插件 xff08 pdf translate xff09 插件二 xff1a 文献附件管理 xff08 ZotFile xff09 插件三 xff1a 中文文献插件 xff08 茉莉花 xf
  • Translate Aticle

    最近在Thinkpad上安装Ubuntu12 04的时候 xff0c 经历了几个问题 xff0c 发现BOIS里多了很多选项 xff0c 而且安装双系统也有UEFI有关 xff0c 在网站上找了一篇文章 xff0c 发现这还是一个新概念 x
  • 需要帮助来理解带有 /d 的 perl tr 命令

    我在网上发现了以下 Perl 示例 usr bin perl string the cat sat on the mat string tr a z b d print string n result b b b 有人可以解释一下吗 d表示
  • Python 翻译多个字符

    我正在尝试在 python 3 3 3 中创建一个程序 它将接受一个字符串 然后将其转换为数字 1 26 我知道如何计算一位数字 但不知道如何计算 2 位数字 translist str maketrans 123456789 ABCDEF
  • 在 WCF 服务中将 DTO <==> 实体转换器放置在哪里?

    我有以下设计 我的设计 我的设计 http s15 postimg org 3zha8rzqh Design Idea png 我的课程中将有一个名为 ProductDTO 的课程服务层 左侧服务 当调用 更新产品 ProductDTO 操
  • Xamarin Forms - 在运行时翻译抽屉菜单项

    我正在遵循优秀的教程 Link 关于 Xamarin Forms 中的多语言 一切正常 但我有一个问题 在我的应用程序中 我使用 Syncfusion 的导航抽屉 因为我在 ListView 中生成菜单项 如下所示 DrawerPage x
  • Zend Framework 2 - 翻译路线

    我想知道是否可以在 zf2 中使用路由 uri 的翻译工具 我想要例如路线en domain tld article show 1例如翻译为de domain tld artikel anzeigen 1 我不认为正则表达式是这里的方法 因
  • Python ValueError:chr() arg 不在范围内(256)

    所以我正在学习python并重做一些旧项目 该项目涉及从命令行获取字典和要翻译的消息 并翻译该消息 例如 btw 你好 你好 将被翻译为 顺便说一句 你好 你好吗 我们使用教授提供的扫描仪来读取标记和字符串 如果有需要我也可以在这里发布 这
  • 我尝试使用动画来使线性布局进行翻译,像这样向左<->向右。但我遇到了一些错误

    这是我的第一个应用程序 我尝试从右到左或从左到右翻译 这是代码 资源 gt 动画 gt 向左翻译
  • 根据元素高度和宽度转换 X 和 Y 百分比值?

    将元素 Y 轴平移 50 会将其向下移动自身高度的 50 而不是我所期望的父级高度的 50 如何告诉翻译元素将其翻译百分比基于父元素 或者我不明白什么 http jsfiddle net 4wqEm 2 http jsfiddle net
  • 将 OS X Bash 脚本翻译为 Windows

    I use Hedge https hedge video 转移幻灯 https www magiclantern fm 在我的 Canon 5D Mark III 上拍摄的视频文件 在 OS X 上 我可以使用 Automator 设置
  • 如何使用 Google Translator Api 将转换后的英文文本设置到另一个文本框?

    我有两个文本框 一个用于英语 另一个用于印地语 当我在第一个框中输入英语时 文本应在第二个框中显示为印地语版本 在按键事件上 我已经提到了一个例子如何在您的网站中通过 Google API 将英语翻译成印地语 http arunsonare
  • 将视图从一种布局动画化到另一种布局

    检查附图以方便解释 翻译动画可以工作 但它会在同一视图内进行动画处理 我希望视图从一种布局飞出到另一种布局 我从这里的另一个答案尝试过这个 相同布局的动画 public class Animations public Animation f
  • 颠倒 d3.zoom 缩放和平移的顺序

    如果您单击本例中的红色按钮 https bl ocks org interwebjill fe782e6f195b17f6fe6798a24c390d90 https bl ocks org interwebjill fe782e6f195
  • Laravel 翻译 required_if 值

    我正在使用 Laravel 版本 5 2 45 目前我在翻译 required if 规则时遇到一些麻烦 当我使用 required if field value 时 它 会打印错误验证消息中的字段值 在本例中为 1 或 0 这不太可读 例
  • Angular 5 - 在 TypeScript 中翻译字符串

    我使用 i18n 进行翻译 并且对它在 html 方面的工作方式感到满意 但是 如果我在打字稿的字符串中定义了错误消息等 我想要一种方法来翻译这些内容 但找不到方法来做到这一点 有解决方法可以实现这一目标吗 到目前为止 通过库的 API 还
  • 安卓。谷歌 API 翻译

    我在集成 Google API Translate 时遇到一些问题 添加到 gradle 配置此依赖项 compile com google apis google api services translate v2 rev41 1 20
  • Pyspark 删除数据帧列中的多个字符

    看看 pyspark 我明白了translate and regexp replace帮助我了解数据框列中存在的单个字符 我想知道是否有一种方法可以在regexp replace or translate这样它就会解析它们并用其他东西替换它

随机推荐

  • vue.config.js 配置的文件

    vue config js是一个可选的配置文件 用于配置Vue CLI构建的项目 如webpack的配置等 使用vue config js 可以在项目的根目录下创建一个JavaScript文件 并在该文件中进行配置 下面是一些在vue co
  • JAVA-JDK1.8介绍

    Java JDK 1 8 Java Development Kit的第8个主要版本 Java JDK 1 8是Java编程语言的一个重要版本 引入了一些新的功能和改进 同时也修复了几项bug 在本博客中 我将详细介绍Java JDK 1 8
  • ESP8266常见问题汇总——转载自官网

    ESP8266 常见问题 本页面收集esp8266常见问题 概述 本文档主要介绍开发者在ESP8266开发中常见的一些问题 这些问题主要包括以下几大类 基本概念相关 ESP8266 相关 AiCloud 相关 固件编译调试相关 文档资料相关
  • leetcode 376 摆动序列

    动态规划 class Solution public int wiggleMaxLength int nums if nums length 1 return nums length 动态规划 dp i 0 表示当前数字的子序列长度 dp
  • rabbitmq Attempting to connect to: [localhost:5672] SocketExceptio:Socket Closed

    今天使用spring cloud stream for rabbitmq启动项目报错 2019 05 03 13 22 27 350 INFO file 18160 main o s a r c CachingConnectionFacto
  • FAPI专题-8:5G FAPI接口 - 中文规范-4- P7消息格式

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 120645757 目录 第3章 主要的
  • 若依管理系统RuoYi-Vue(二):权限系统设计详解

    本篇文章试图讲解若依Vue系统中的权限设计原理以及实战 为什么是 试图 因为这也是摸索着理解的 不一定准 若依Vue系统中的权限管理部分的功能都集中在了系统管理菜单模块中 如下图所示 其中权限部分主要涉及到了用户管理 角色管理 菜单管理 部
  • nginx中root与alias关键字的区别

    前言 近段时间秋招上岸了 于是每天疯狂补各种分布式基础 每天都在痛苦与快乐中度过 在学习 nginx 的时候 遇到配置上的问题 root 与 alias 的区别 卡了大概三个小时 记录下来警醒自己不要再犯了 正文 在使用 进行配置时 两者没
  • CentOS yum的详细使用方法

    yum 是什么yum Yellow dog Updater Modified主要功能是更方便的添加 删除 更新RPM包 它能自动解决包的倚赖性问题 它能便于管理大量系统的更新问题 yum特点可以同时配置多个资源库 Repository 简洁
  • DirectShow播放视频步骤

    DirectShow是MicrosoftWindows平台上的流媒体架构 可以用它来方便的进行视频捕获和回放 DirectShow是基于组件对象模型 COM 下面是DirectShow播放AVI视频的代码 include
  • java项目-谷粒商城(持续更新ing)

    使用docker安装nacos 我是直接在网上找的教程 17条消息 Docker下载安装Nacos并完成持久化配置 docker nacos 下载 虫链Java Library的博客 CSDN博客 在项目中导入依赖 在 common 项目中
  • [0x7FFE1E17E050] ANOMALY: meaningless REX prefix used

    今天要记录一下糟糕的事情 遇到一个很是 cao dan 的问题 再用git时 报错了 0x7FFE1E17E050 ANOMALY meaningless REX prefix used 在cmd窗口输入 也报这个错 idea中也报错 gi
  • 云原生——云平台操作

    作者介绍 奇妙的大歪 个人名言 但行前路 不负韶华 个人简介 云计算网络运维专业人员 前言 云 云是网络 互联网的一种比喻说法 平台 即操作系统 数据库和一些中间件都可称为软件平台 云计算 使用互联网接入存储或者运行在远程服务器端的应用 数
  • 3dsMax2016卡死的一种解决办法

    可能是升级win10版本的时候 win10自带的输入法也升级了 然后3dsMax2016就卡死了 设置一下输入法的兼容性
  • Vue基础知识总结 7:插槽slot与vue导入导出

    作者简介 哪吒 CSDN2021博客之星亚军 新星计划导师 博客专家 哪吒多年工作总结 Java学习路线总结 搬砖工逆袭Java架构师 关注公众号 哪吒编程 回复1024 获取Java学习路线思维导图 大厂面试真题 加入万粉计划交流群 一起
  • 基于matlab实现信号的线性卷积与循环卷积

    系列文章目录 数字信号处理 DSP Digital Signal Process 是电子通信领域非常重要的研究方向 博主汇总了数字信号处理 DSP 中常用的经典案例分析 主要基于算法分析 MATLAB程序实现 信号图像显示 对数字信号处理的
  • python flask框架下登录注册界面_基于Flask框架如何实现用户登录功能

    form hidden tag form username class form control input lg placeholder 用户名 form password class form control input lg plac
  • dubbo解析-@EnableDubbo注解详解

    本文基于dubbo 2 7 5版本代码 文章目录 一 EnableDubbo注解功能 二 详细介绍注解引入的三个类的作用 dubbo必须配置注解 EnableDubbo 一 EnableDubbo注解功能 EnableDubbo整合了三个注
  • MetaFormer/PoolFormer学习笔记及代码

    MetaFormer PoolFormer学习笔记及代码 MetaFormer Is Actually What Y ou Need for Vision code https github com sail sg poolformer A
  • RN仿微信朋友圈图片拖拽删除

    目录 前言 初始时 渲染时 开始拖拽 拖拽中 拖拽结束 拖拽删除 参考链接 前言 之前负责的一个需求 让在RN端做仿微信朋友圈的图片删除和排序 由于经验和时间限制 就跟PM协商改为点击删除 由此欠下一个技术栈 今天是来还债的 本文基于tra