不多说,我们肯定遇到过这个需求:

把一个控件从当前位置移动到另一个位置。可能需求最多的就像是支付宝应用页面的编辑:

比如,我想把最近使用的 红包 添加到 我的应用 当中,支付宝这里是用的 + 号。

那如果产品说我就想让它拖过去,这可咋整?

不慌,Flutter 也为我们提供了相关的 Widget。

Draggable

Flutter 如果要实现这种效果,那么非 Draggable 不可。

照例我们查看官方文档。

A widget that can be dragged from to a DragTarget.

可拖动到 DragTarget 的小部件。

复制代码

那也就是说,除了 Draggable ,还有一个 DragTarget。

DragTarget 是用来接收我们拖过去的 Widget 的,我们后面再说。

先说Draggable。

在官方文档找了一圈没发现Demo,那没办法了,直接开撸。

先看构造函数:

class Draggable extends StatefulWidget{

/// Createsawidget that can be dragged toa[DragTarget].

///

/// The [child] and [feedback] arguments must not be null. If

/// [maxSimultaneousDrags] is non-null, it must be non-negative.

const Draggable({

Key key,

@required this.child,

@required this.feedback,

this.data,

this.axis,

this.childWhenDragging,

this.feedbackOffset = Offset.zero,

this.dragAnchor = DragAnchor.child,

this.affinity,

this.maxSimultaneousDrags,

this.onDragStarted,

this.onDraggableCanceled,

this.onDragEnd,

this.onDragCompleted,

this.ignoringFeedbackSemantics = true,

}) : assert(child != null),

assert(feedback != null),

assert(ignoringFeedbackSemantics != null),

assert(maxSimultaneousDrags == null || maxSimultaneousDrags >= 0),

super(key: key);

}

复制代码

可以看到该类还支持泛型,这个泛型是来界定 data的,后面再说。

先来看看必须的参数,child 和 feedback。

child 应该不比多说,说一下 feedback。

点击查看feedback 参数,上面的注释这样写着:

当拖动正在进行时在指针下显示的小部件。

既然搞懂了必传参数,那就开撸:

Widget _createGridView(List _items) {

return GridView.builder(

itemCount: _items.length,

shrinkWrap: true, // 相当于Android的 wrap_content ,也就是包裹住该 widget的高度

physics: NeverScrollableScrollPhysics(), // 不允许滑动

padding: EdgeInsets.all(10),

gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(

crossAxisCount: 5, // 设置 gridview 每一行的数量

mainAxisSpacing: 10,

crossAxisSpacing: 10,

),

itemBuilder: (context, index) {

return Draggable( // 返回一个Draggable

// 必须要一个Material,不然拖动时Text会有双下划线

feedback: Material(

child: Container(

height: 100,

width: 100,

color: Colors.blueAccent,

alignment: Alignment.center,

child: Text(

_items[index],

style: TextStyle(color: Colors.white),

),

),

),

child: Container(

color: Colors.blueAccent,

alignment: Alignment.center,

child: Text(

_items[index],

style: TextStyle(color: Colors.white),

),

),

);

},

);

}

复制代码

我们定义一个 GridView,里面每一个 item 都是一个 Draggable。

来运行一下看效果:

可以看到我们确实是可以拖动了,大功已经告成一半了。

那么我们下面开始定义接收的部件 DragTarget。

DragTarget

废话也不多说,直接看构造函数,看看什么是必填:

class DragTarget extends StatefulWidget{

/// Createsawidget that receives drags.

///

/// The [builder] argument must not be null.

const DragTarget({

Key key,

@required this.builder,

this.onWillAccept,

this.onAccept,

this.onLeave,

}) : super(key: key);

}

复制代码

可以看到必传的参数也就是一个builder,用来构建我们的页面使用。

其他参数看名字也都能明白:

onWillAccept 拖到该控件上时调用

onAccept 放到该控件时调用

onLeave 没有放到该控件时调用

那我们这里只需要一个确认已经放到该控件时的回调,来接收我们传过来的值。

撸码:

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text('DraggablePage'),

),

body: Column(

children: [

_createGridView(_items1),

SizedBox(height: 100,),// 占位

DragTarget(// 用来接收数据的 Widget

builder: (

BuildContext context,

List accepted,

List rejected,

) {

return _createGridView(_items2);

},

// 用来接收数据

onAccept: (String data) {

setState(() {

_items2.add(data);

});

},

)

],

),

);

}

复制代码

这是完整的 build 代码,但是还需要改造一下我们的 Draggable 。

再看一下Draggable的构造函数:

class Draggable extends StatefulWidget{

/// Createsawidget that can be dragged toa[DragTarget].

///

/// The [child] and [feedback] arguments must not be null. If

/// [maxSimultaneousDrags] is non-null, it must be non-negative.

const Draggable({

Key key,

@required this.child,

@required this.feedback,

this.data,

this.axis,

this.childWhenDragging,

this.feedbackOffset = Offset.zero,

this.dragAnchor = DragAnchor.child,

this.affinity,

this.maxSimultaneousDrags,

this.onDragStarted,

this.onDraggableCanceled,

this.onDragEnd,

this.onDragCompleted,

this.ignoringFeedbackSemantics = true,

}) : assert(child != null),

assert(feedback != null),

assert(ignoringFeedbackSemantics != null),

assert(maxSimultaneousDrags == null || maxSimultaneousDrags >= 0),

super(key: key);

}

复制代码

因为如果想要传入数据,那也就必须要有数据可以传,也就是我们构造函数里看到的 data 字段。

还需要删除我们的源数据,那也就是要监听拖动结束的回调,这里就是 onDragCompleted。

我们来看改造后的Draggable:

Widget _createGridView(List _items) {

return GridView.builder(

itemCount: _items.length,

shrinkWrap: true,

physics: NeverScrollableScrollPhysics(),

padding: EdgeInsets.all(10),

gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(

crossAxisCount: 5,

mainAxisSpacing: 10,

crossAxisSpacing: 10,

),

itemBuilder: (context, index) {

return Draggable(

onDragCompleted: (){

// 在拖动结束后删除数据

setState(() {

_items.removeAt(index);

});

},

feedback: Material(

child: Container(

height: 100,

width: 100,

color: Colors.blueAccent,

alignment: Alignment.center,

child: Text(

_items[index],

style: TextStyle(color: Colors.white),

),

),

),

// 当前组件的数据

data: _items[index],

child: Container(

color: Colors.blueAccent,

alignment: Alignment.center,

child: Text(

_items[index],

style: TextStyle(color: Colors.white),

),

),

);

},

);

}

复制代码

运行看一下效果:

可以看到这样就基本完成我们的需求了,但是有人说,能不能把我拖着的源控件加个特效?

没问题,我们通过 childWhenDragging参数来控制。

如,加个蒙层:

childWhenDragging: Container(

color: Colors.blueAccent,

alignment: Alignment.center,

foregroundDecoration: BoxDecoration(color: Colors.white30),

child: Text(

_items[index],

style: TextStyle(color: Colors.white),

),

),

复制代码

添加一个foregroundDecoration 就ok了,效果如下:

总结

通过这个小例子我们可以实现特别多的效果。

而且默认拖动的控件时可以多指触控的,也就是说我们可以同时拖动N个控件。

可以通过 Draggable 的 maxSimultaneousDrags 来控制。

构造函数里其他的参数大家可以自行了解一下。

不得不说 Flutter 是真的好用。

关注我,每天更新 Flutter & Dart 知识。

flutter 拖拽布局_Flutter 史上最牛拖动控件 Draggable相关推荐

  1. flutter 拖拽布局_使用Flutter模仿SOUL可任意拖动的悬浮按钮

    在Flutter中,我们可以两种方式实现小部件对拖动效果 GestureDetector() Draggable() GestureDetector 在开发过程中经常使用到GestureDetecto ...

  2. Unity UGUI基础 之 Scroll View/Scroll Rect 的简单使用,并取消拖拽(滑动内容)效果,拖拽只在Scrollbar 上起作用

    Unity UGUI基础 之 Scroll View/Scroll Rect 的简单使用,并取消拖拽(滑动内容)效果,拖拽只在Scrollbar 上起作用 目录 Unity UGUI基础 之 Scro ...

  3. Flutter拖拽控件Draggable

    Draggable 最近做了一个Flutter项目,其中有一个需求是做出三个可以互相拖拽的任务列表,平时在做Android项目时,拖动的控件基本上都是自定义View来实现的,想看看在Fluter上大家 ...

  4. 拖拽或点击上传(支持苹果safari浏览器)

    <input type="file" value="上传">  拖拽或点击上传(在safari浏览器不支持拖拽),主要解决safari浏览器的拖拽问 ...

  5. 基于layui.upload.js 拖拽文件/文件夹上传下载

    layui.upload.js 拖拽文件/文件夹上传下载 前言 js代码 页面使用(我这里用的是uploader.jsp) CSS文件 上传效果 总结 前言 项目需求完成文件上传,可以拖拽上传文件/文 ...

  6. 第19节 三个败家子 19 ——史上最牛太守孙坚

    分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow 中国的面子问题,是 ...

  7. 第19节 三个败家子(19)——史上最牛太守孙坚

    中国的面子问题,是一种很奇特的文化现象,可以说举凡中国人就没有不好面子的.尤其对中国男性来说,不好面子的那部分人你干脆可以将他排斥到男性同胞之外. 所谓"饿死事小,面子事大",饿不 ...

  8. 史上最牛员工将退休 23年每天挣10亿(图)

    史上最牛员工将退休 23年每天挣10亿(图) 其实现在越来越感觉很多道理都是相通的,而很多大道理都是实用的.比如本文介绍的很多经验,也适用于科研~~ 原标题:史上最牛员工每天挣10亿,记录保持23年! ...

  9. 号称史上最牛逼的几篇博客整理(python+java+js等)

    号称史上最牛逼的几篇博客这个说法也许夸张了点,但总体来说楼主整理的博客都是楼主幸苦之作,并且都是围绕去转盘网展开,这些博客几乎透漏了该站的所有技术关键,细节,甚至所有核心代码,我个人认为作为一个有艺术 ...

最新文章

  1. 基于WeUI的Angular2开发
  2. Linux ubuntu中怎么生成随机数,随机数的生成
  3. python如何读取excel数据-python怎么读取excel中的数值
  4. 关于Qt、Qt/E、Qtopia、qvfb、framebuffer、qpe等概念的对比介绍
  5. [Win10应用开发] 使用 Windows 推送服务 (WNS)
  6. vim学习(2)小幅提升
  7. 指点聚源码论坛全站源码 WordPress内核
  8. 【sql进阶】查询每天、每个设备的第一条数据
  9. 【英语学习】【Level 08】U01 Let's Read L1 All the world's a stage
  10. Element ui 中的Upload用法
  11. [操作系统] FAT文件系统概述
  12. 6. 测度论-期望及其性质
  13. linux手机 电脑传文件怎么安装,centos7上成功安装iptux,成功实现安卓手机和Linux传送文件...
  14. 用SPSS求均值 方差 标准差小例题
  15. 面对工业4.0,我国工业企业的挑战与对策
  16. 83. 测试是软件开发的工程严谨度
  17. 虚拟机VMware Workstation安装使用教程
  18. 大厂成熟Foc电机代码STM32f031C6. 把原先的原理图,给整理了
  19. 佳能mg3150pixma_升级到佳能Pixma MP500多功能喷墨打印机
  20. Angular2+简单入门

热门文章

  1. request.path 值危险
  2. IE7下position:relative的问题
  3. WayOs 聊天软件号码登记器,让找人变得更简单
  4. 数据库事务必须具备的特性:ACID【转】
  5. (篇一)作为一个程序猿,这些C语言实例你必须会!
  6. 从零开始学前端:CSS元素模式的转换和CSS三大特性 --- 今天你学习了吗?(CSS:Day12)
  7. Python计算组合数生成杨辉三角形
  8. Python+pyplot绘制带文本标注的柱状图
  9. 转义字符'\r'在Python内置函数print()中的妙用
  10. 使用Python对图像进行中值滤波