【Flutter】在Flutter中实现长按拖拽排序?不要太轻松,Reorderables 开源项目介绍和源码分析(作者的思路挺鬼才的,我怎么想不到)

前言

今天是复工的第一天,现在还是不太能接受假期就这么结束了,就当是一场梦,醒了很久还是很不能接受;

回正题,

这篇的主题在Flutter中实现拖拽排序可以怎么做;

当然,flutter 中本身就带有 ReorderableListView 这个控件,不过如果需要对 GridView、瀑布流这种来做一个拖拽排序的话,flutter本身并没有类似 ReorderableGridView 这种东西;

这时候就到了万能的 pub.dev 上场的时候了

reorderable 介绍

目前在pub上搜索reorder这个关键词,相关部分中,like最多的就是 [reorderable],

按照其描述,提供了多种类型的可排序组件,

其中有一个ReorderableWrap 就是我需要的效果……额,应该说一部分;也就是这次要说的内容:长按拖拽排序;

reorderable 的实现原理

还是老样子,先带着问题分析过程:

先对其实现过程提出这么几个问题:

  • 长按之后会在原地留下个虚影,这个是怎么实现的;
  • 移动到其他Item的时候,是怎么判断插入到目标Item的前面还是后面的?
  • 排序之后,其他Item依次往后或者往前移动,这个效果是怎么实现的?

要解决这些问题,首先要看下基本机构和原理:

要了解基本机构,就要来到build方法:

build 方法快速一览:

build方法最终返回的东西,其实默认是一个Wrap,也就是那个defaultBuildItemContainer构造出来的,所以可疑的部分来到了wrappedChildren:

image.png

而这个wrappedChildren,仅仅是对child包了一层?????看来核心是这个_wrap 方法?

image.png

不过值得警觉的是,这里好像,做了个排序,先记一下:

image.png

那么来看下这个值得怀疑的_wrap方法:

_wrap 方法快速一览

_wrap 方法挺长的,不过还是先看return 部分;

image.png

_wrap 的 return 这块 ,_buildContainerForMainAxis 方法是返回一个 wrap ,对于了解结构这块,好像意义不大;

_includeMovedAdjacentChildIfNeeded 有点意思,是根据 _ghostDisplayIndex 和 _currentDisplayIndex ,以及传入的 childDisplayIndex ,对构造的 dragTarget 进行一个改造,判断是否需要添加 disappearingPreChild ,以及添加的顺序,这里先放一下,毕竟这几个参数是干啥用的,也不知道;

下面这个 dragTarget ,就是Reorderables实现的核心点了;

image.png

dragTarget 是一个stack,由三层组成:containedDraggable.builder ; 位置在left、top的一半大小的preDragTarget,以及在right、bottom,同样一半大小的nextDragTrget;

其实应该有人看出来了,不止这里,前面也多次出现过 Draggable 和 DragTarget 相关的部分的词语;

所以其实核心技术点就是Draggable跟DragTarget的组合使用;preDragTarget 跟 nextDragTarget 这两块也确实的出现了DragTarget

image.png

而上面提到的 containedDraggable.builder ,其实就是Draggable:

image.png image.png

所以结构也很清楚了,总结一下的话就是

在Wrap的容器内有数个Item,每个Item都是一个Stack,里面除了item的内容外,还分别在两边各放一半的SizeBox来当作DragTarget;

基本结构了解完,貌似部分问题其实就有答案了……

长按留下的虚影的实现方式:

Draggable提供了 childWhenDragging 方法,以供在拖拽的时候在原地留个占位;

那么将这个占位做个半透明处理,那不就是虚影了?

image.png

Item拖拽到指定位置后,移动位置的判断方式:

正如上面在基本结构分析中所述,每个Item,其实都包含了两个DragTarget,各占一半;拖拽到哪个DragTarget,哪个DragTarget做出响应即可:

image.png

依次移动动画的实现方式:

知道了位置之后,插入的动画怎么实现,就要看这个 onWillAccept方法,它是怎么处理响应的:

首先是对一些参数进行计算,做一些边界判断,以及判断滑动响应的Item是自己本身对应的,那就不做响应,之类的东西:

image.png

下面这块就是真正去响应操作,触发动画的部分了:

image.png

在这里触发一次 setState ,修改 _nextDisplayIndex , 触发_requestAnimationToNextIndex

参数这块先不管,setState总体完成后再看看具体作用,那么看下这个_requestAnimationToNextIndex 方法:

image.png

这里的作用就是设置 _ghostDisplayIndex、_currentDisplayIndex 这两个参数的值,并触发了两个AnimationController

话说,这个_ghostDisplayIndex、_currentDisplayIndex , 是不是在哪里见过???

好像,build方法中,会根据_currentDisplayIndex 做个排序?

那么setState的作用就清楚了,直接排序,并将已经处于 childWhenDragging 状态的Item 插入过去,这样,虚影就显示到目标位置了;

而这两个AnimationController的作用,就要看其调用位置了

在前面的贴图中,可以看到,很多部分,Item的显示内容,都会包一层东西,比如说 childWhenDragging 那块,child是一个 _makeAppearingWidget ,builder方法也是,会往List中加入 _makeDisappearingWidget 构造出的widget;

总结一下的话,就是会往目标位置跟拖动Item中的Item放入_makeAppearingWidget跟_makeDisappearingWidget包裹的Item

其实这两个Controller就是控制这两个Widget的,一个负责处理添加的时候后移操作动画,一个负责处理移走的前移操作动画;

image.png

而其实现方式也简单:

image.png

没错,用SizeTranstion,通过动画改变Item大小,把后面的Item挤过去……

总结一下:

setState 后build方法将要拖拽的Item移动到目标位置,这时候Item本身的大小为0,随着动画的播放,SizeTranstion 逐渐改变Item的大小,后面的部分就这么给挤过去了……(这方法我当时确实没想到,还可以这么玩~~~)

当然会对特殊情况做个小处理:

image.png

当发生跨行的时候,让跨行的第一个Item也执行由小变大的动画;

结语

这作者的操作确实让人开眼界,我当时还以为要通过OverLay之类的东西来搞,没想到其实实现方式没必要那么复杂,这不挺简单的嘛:

国际惯例,效果图:

在这里插入图片描述

下面就是搞搞这个的改造,加入那个文件夹功能;

总结

要想成为架构师,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

一、架构师筑基必备技能

1、深入理解Java泛型
2、注解深入浅出
3、并发编程
4、数据传输与序列化
5、Java虚拟机原理
6、高效IO
……

在这里插入图片描述

二、Android百大框架源码解析

1.Retrofit 2.0源码解析
2.Okhttp3源码解析
3.ButterKnife源码解析
4.MPAndroidChart 源码解析
5.Glide源码解析
6.Leakcanary 源码解析
7.Universal-lmage-Loader源码解析
8.EventBus 3.0源码解析
9.zxing源码分析
10.Picasso源码解析
11.LottieAndroid使用详解及源码解析
12.Fresco 源码分析——图片加载流程

在这里插入图片描述

三、Android性能优化实战解析

  • 腾讯Bugly:对字符串匹配算法的一点理解
  • 爱奇艺:安卓APP崩溃捕获方案——xCrash
  • 字节跳动:深入理解Gradle框架之一:Plugin, Extension, buildSrc
  • 百度APP技术:Android H5首屏优化实践
  • 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
  • 携程:从智行 Android 项目看组件化架构实践
  • 网易新闻构建优化:如何让你的构建速度“势如闪电”?

在这里插入图片描述

四、高级kotlin强化实战

1、Kotlin入门教程
2、Kotlin 实战避坑指南
3、项目实战《Kotlin Jetpack 实战》

  • 从一个膜拜大神的 Demo 开始

  • Kotlin 写 Gradle 脚本是一种什么体验?

  • Kotlin 编程的三重境界

  • Kotlin 高阶函数

  • Kotlin 泛型

  • Kotlin 扩展

  • Kotlin 委托

  • 协程“不为人知”的调试技巧

  • 图解协程:suspend

在这里插入图片描述

五、Android高级UI开源框架进阶解密

1.SmartRefreshLayout的使用
2.Android之PullToRefresh控件源码解析
3.Android-PullToRefresh下拉刷新库基本用法
4.LoadSir-高效易用的加载反馈页管理框架
5.Android通用LoadingView加载框架详解
6.MPAndroidChart实现LineChart(折线图)
7.hellocharts-android使用指南
8.SmartTable使用指南
9.开源项目android-uitableview介绍
10.ExcelPanel 使用指南
11.Android开源项目SlidingMenu深切解析
12.MaterialDrawer使用指南
在这里插入图片描述

六、NDK模块开发

1、NDK 模块开发
2、JNI 模块
3、Native 开发工具
4、Linux 编程
5、底层图片处理
6、音视频开发
7、机器学习

在这里插入图片描述

七、Flutter技术进阶

1、Flutter跨平台开发概述
2、Windows中Flutter开发环境搭建
3、编写你的第一个Flutter APP
4、Flutter开发环境搭建和调试
5、Dart语法篇之基础语法(一)
6、Dart语法篇之集合的使用与源码解析(二)
7、Dart语法篇之集合操作符函数与源码分析(三)

在这里插入图片描述

八、微信小程序开发

1、小程序概述及入门
2、小程序UI开发
3、API操作
4、购物商场项目实战……

在这里插入图片描述

全套视频资料:

一、面试合集
在这里插入图片描述
二、源码解析合集

在这里插入图片描述
三、开源框架合集

在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取【保证100%免费】↓↓↓
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flutter,可以使用以下步骤来实现启动广告页: 1. 在pubspec.yaml文件添加flutter_svg插件,以便加载SVG图片: dependencies: flutter_svg: ^0.22.0 2. 创建一个新的类,例如SplashScreen,来显示启动广告页。在这个类,可以使用Stack Widget来叠加一个Image或SVG图片和一个倒计时Widget。 import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; class SplashScreen extends StatefulWidget { @override _SplashScreenState createState() => _SplashScreenState(); } class _SplashScreenState extends State<SplashScreen> { int _countdown = 3; @override void initState() { super.initState(); startTimer(); } void startTimer() { Timer.periodic(Duration(seconds: 1), (timer) { setState(() { if (_countdown > 1) { _countdown--; } else { timer.cancel(); // 跳转到主页 } }); }); } @override Widget build(BuildContext context) { return Scaffold( body: Stack( fit: StackFit.expand, children: [ SvgPicture.asset( 'assets/images/splash_screen.svg', fit: BoxFit.cover, ), Positioned( top: 40, right: 40, child: GestureDetector( onTap: () { // 跳过广告,直接跳转到主页 }, child: Container( padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), decoration: BoxDecoration( color: Colors.black54, borderRadius: BorderRadius.circular(20), ), child: Text( '跳过 $_countdown', style: TextStyle( color: Colors.white, fontSize: 16, ), ), ), ), ), ], ), ); } } 3. 在主Flutter应用程序,将SplashScreen作为Navigator的第一个页面,以便在启动时显示。 void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'MyApp', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, ), home: SplashScreen(), // 启动广告页 ); } } 通过上述步骤,即可在Flutter实现启动广告页。可以根据具体需求,调整广告图片、倒计时时间和跳过广告的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值