Flutter进阶技巧之300行代码实现拖拽排序

前言

有没有不计算,代码少的方式来实现这个拖拽排序呢?

文末有福利!!!

效果设计

拖拽排序这块,其实最复杂的部分就是排序动画的处理,在 reOrderables 中,可以说绝大部份代码都是为了定位排序位置,最后通过调整Size,用AnimationController辅助处理,这种方式来实现一个折叠动画;

说实话,效果是有了,但是这代码确实让人看的容易晕;

在 Android 中,其实更多的排序动画是类似这种平移动画的:

demo.gif

所以这次我也计划使用这种动画实现(其实就是懒);

当然,该有的虚影之类的也是应该有的东西;

实现方案:

获取各个Item的位置信息

要想实现上面的平移动画,第一步就是知道各个Item自己本身在GridView中的位置坐标;

关于获取位置的实现方式,大部分方案都是通过给各个Item加上GlobalKey,然后获取renderObject来测量;

不过这次玩点花的,我想尽量少些代码的同时,减少GlobalKey的数量;

众所周知,sliver在layout方法结束后,会调用 didFinishLayout 方法,来通知layout结束,并公布当前缓存的第一个和最后一个Item的index;

既然这样,我在layout方法结束的时候,获取一下各个Item所在的起始位置不就行了?

提供一个共享Item位置的 InheritedWidget

这个InheritedWidget的作用,就是保存两个列表,分别存放Item的实际位置和重排序位置:

image.png

至于这两个List干啥用的,后面再揭秘;

PS : 其实用List存放位置信息是不合适的,因为List中的第一个Item,并不一定是GridView中index = 0 的那个Item,所以最后处理的时候要做一个index的转换,比较麻烦;

我这里偷懒,先用List存了

给我一个Key,还你一片Offset

继承GridView,重写buildChildLayout , 给SliverGrid设置一个GlobalKey:

image.png

这个 Key 的作用,就是获取 SliverGrid 的 Element;而通过 Element 就可以拿到 各个child 对应的Element;

不过这里稍微不同的是,由于所说方法名是didFinishLayout,但是实际上,这里是performLayout方法的最后一步而已,所以performLayout方法实际上是没有完成的;

因此parent默认是不允许访问child的size的,如果调用renderOject.localToGlobal就会报错;

既然这样,可以用另一种方式获取child的位置信息,比如说,ParentData:

image.png

PS :其实Key这玩意也可以不用设置,在前面对Sliver的分析中已经知道了,调用 SliverChildDelegate 的 didFinishLayout方法的就是 SliverGrid 的 Element ,说白了,如果勤奋点,把 sliver那块重写下,就可以把Element传过来了;

同时因为 Element 可以视为 BuildContext , context 也能拿到,进而也能用来获取InheritedWidget,共享数据也很方便,当然这里是放到build方法中获取InheitedWidget来偷懒;

所以我感觉最合适的方法是重写sliver以及这个SliverChildDelegate……

懒人福音 AnimatedContainer

在这里对build的Item进行一定的处理,首先最外层包一层AnimatedContainer:

image.png

AnimatedContainer 可以说是一个全自动动画播放器,没有AnimationController和Tween,仅仅一个setState就可以方便的实现切换动画;

而前面存放的两个List中的内容,就在这里用上了:

只需要把两个Item的Offset一减,setState之后就能实现位置平移动画;

PS:这个方案来自一位德国小哥的项目

不过我感觉他也写的挺麻烦的,没有结合DragTarget,而是仅仅通过Draggable返回的手势信息来做的碰撞检测,看的有点眼花……😵‍💫

PPS : 我知道他为什么不用DragTarget了……GridView本身的hitTest,是根据主轴交叉轴信息修改了点击坐标位置的,但是AnimatedContainer 中加入Transform后,这个坐标再次经过修改后,就根本命中不了任何一个Item…………所以,当Item通过Transform改变位置后,Draggable和DragTarget 是不会响应任何手势的……

至于这两个List中的内容是如何改变的,就是下面这部分了:

Pull My “Draggable” Trigger !

这里就来到了熟悉的Draggable+DragTarget部分:

在上图中,最后构造出的Item是一个Stack,其中原本 Item 应有的 child 传递给了buildDraggable方法构造Draggable;

另一部分就是DragTarget ,关键部分就在这里,其所做的事其实就是检测到碰撞后,根据自己和碰撞Item的index,重排序一下:

image.png

最后通过回调,触发外面的setState,启动动画即可:

结语:

两个文件共计不到300行:

image.png

image.png

虽说不到300行实现了目标效果,不过bug还是有的,比如说再次滑动切换DragTarget的时候,位置信息就算错了,估计某个状态没存上,onDragEnd之后通知保存数据这块也没做处理

但是300行确实能实现核心逻辑,剩下的东西都是些边边角角的部分,多也多不到哪去……吧,大概吧~~~~~

回正题:国际惯例,看下效果:

更新:

后来看了下,这块还真没法用Draggable+DragTarget 的方案,还真只能靠Draggale返回的手势回调来做计算…………

原因就是AnimatedContainer 这块中的PPS补充部分……

不计算这个目标流产了……

通过计算的方式估计要加个200行代码……

或者说有什么方案能让GridView的Item移动,但DragTarget不移动呢………… 比如说用Stack往Grid上面覆盖一层,用来放DragTarget呢 …………

部分……

不计算这个目标流产了……

通过计算的方式估计要加个200行代码……

或者说有什么方案能让GridView的Item移动,但DragTarget不移动呢………… 比如说用Stack往Grid上面覆盖一层,用来放DragTarget呢 …………

最后

按照国际惯例,给大家分享一套十分好用的Android进阶资料:《全网最全Android开发笔记》。

整个笔记一共8大模块、729个知识点,3382页,66万字,可以说覆盖了当下Android开发最前沿的技术点,和阿里、腾讯、字节等等大厂面试看重的技术。

好啦,这份资料就给大家介绍到这了,有需要详细文档的小伙伴,可以微信扫下方二维码回复JJ免费领取哈~

图片

图片

因为所包含的内容足够多,所以,这份笔记不仅仅可以用来当学习资料,还可以当工具书用。

如果你需要了解某个知识点,不管是Shift+F 搜索,还是按目录进行检索,都能用最快的速度找到你要的内容。

相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照整个知识体系编排的。

(一)架构师必备Java基础

1、深入理解Java泛型

2、注解深入浅出

3、并发编程

4、数据传输与序列化

5、Java虚拟机原理

6、高效IO

……

图片

(二)设计思想解读开源框架

1、热修复设计

2、插件化框架设计

3、组件化框架设计

4、图片加载框架

5、网络访问框架设计

6、RXJava响应式编程框架设计

……

图片

(三)360°全方位性能优化

1、设计思想与代码质量优化

2、程序性能优化

  • 启动速度与执行效率优化
  • 布局检测与优化
  • 内存优化
  • 耗电优化
  • 网络传输与数据储存优化
  • APK大小优化

3、开发效率优化

  • 分布式版本控制系统Git
  • 自动化构建系统Gradle

……

图片

(四)Android框架体系架构

1、高级UI晋升

2、Android内核组件

3、大型项目必备IPC

4、数据持久与序列化

5、Framework内核解析

……

图片

(五)NDK模块开发

1、NDK开发之C/C++入门

2、JNI模块开发

3、Linux编程

4、底层图片处理

5、音视频开发

6、机器学习

……

图片

(六)Flutter学习进阶

1、Flutter跨平台开发概述

2、Windows中Flutter开发环境搭建

3、编写你的第一个Flutter APP

4、Flutter Dart语言系统入门

……

图片

(七)微信小程序开发

1、小程序概述及入门

2、小程序UI开发

3、API操作

4、购物商场项目实战

……

图片

(八)kotlin从入门到精通

1、准备开始

2、基础

3、类和对象

4、函数和lambda表达式

5、其他

……

图片

好啦,这份资料就给大家介绍到这了,有需要详细文档的小伙伴,可以微信扫下方二维码回复JJ免费领取哈~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值