A Deep Dive Into Draggable and DragTarget in Flutter
https://medium.com/flutter-community/a-deep-dive-into-draggable-and-dragtarget-in-flutter-487919f6f1e4
This article is the sixth in a series of articles which take an in-depth look at Flutter’s built in widgets.
In this article, we will look at Draggable
and DragTarget
.
Exploring Draggable and DragTargets
Draggable
and DragTarget
allows us drag a widget across screen. First we will look at the basics of Draggables
and DragTargets
then dive into details of customizing them.
Draggable
A “Draggable” makes a widget movable around the screen. Let’s use a chess knight as our example.
Using a DragTarget to drag a chess knight around
The code for this is relatively straightforward:
Draggable(
child: WhiteKnight(
size: 90.0,
),
feedback: WhiteKnight(
size: 90.0,
),
childWhenDragging: Container(),
),
There are three main parts to the Draggable
widget:
- Child: The child parameter is the widget that will be displayed when the draggable is stationary
- Feedback: The feedback is the widget that will be displayed when the widget is being dragged.
- Child When Dragging: The childWhenDragging parameter takes the widget to display in the original place of
child
when the widget is being dragged.
In the example above,we have a white knight as the child
.When the knight is being dragged, we show an empty Container
in its place.
Let’s customize the widget
First, let’s change the feedback parameter.
In the example below, we change the feedback parameter to a white bishop. Now, when the widget is not being dragged, a white knight is shown however as you start dragging, our bishop is shown.
Draggable(
child: WhiteKnight(
size: 90.0,
),
feedback: WhiteBishop(
size: 90.0,
),
childWhenDragging: Container(),
),
Result of the above code:
Now let’s move on to the third parameter, childWhenDragging
. This takes a widget to be displayed in the original position of child
as the widget is being dragged.
We’ll display a white rook when the widget is being dragged:
Draggable(
child: WhiteKnight(
size: 90.0,
),
feedback: WhiteBishop(
size: 90.0,
),
childWhenDragging: WhiteRook(
size: 90.0,
),
),
This becomes:
Restricting motion for Draggables
Setting the axis parameter helps us restrict motion in one dimension only.
Axis.horizontal makes the feedback widget on,y move in the horizontal axis.
Draggable(
axis: Axis.horizontal,
child: WhiteKnight(
size: 90.0,
),
feedback: WhiteBishop(
size: 90.0,
),
childWhenDragging: Container(),
),
Similarly, we also have Axis.vertical for vertical movement.
Adding data to Draggable
Data can be attached to a Draggable
. This is useful to us since we use Draggables
and DragTargets
.
Considering our example, if we were to have multiple chess pieces, each piece would need to have unique data associated with it. Pieces would need properties such as color (White, Black) and type (ie: Rook, Bishop, Knight).
Below shows an example of how data can be attached to a Draggable
for use with DragTarget
.
We will take a look at this more in-depth in the DragTarget section.
Draggable(
child: WhiteKnight(
size: 90.0,
),
feedback: WhiteKnight(
size: 90.0,
),
childWhenDragging: Container(),
data: [
"White",
"Knight"
],
),
Callbacks
The draggable
widget supplies callbacks for actions on the widget.
These callbacks are:
onDragStarted : This is called when a drag is started on a widget.
onDragCompleted : When a draggable
is dragged to a DragTarget
and accepted, this callback is called. We will look atDragTarget
is in the next section.
onDragCancelled : When a draggable
does not reach a DragTarget
or is rejected, this callback is fired.
DragTarget
While a Draggable
allows a widget to be dragged, a DragTarget
provides a destination for the draggable.
For example, in chess, a chess piece is a draggable whereas a square box on the chessboard is a drag target.
Here, the knight is accepted by the DragTarget
.
The code for this example goes:
bool accepted = false;
DragTarget(builder: (context, List<String> candidateData, rejectedData) {
return accepted ? WhiteKnight(size: 90.0,) : Container();
}, onWillAccept: (data) {
return true;
}, onAccept: (data) {
accepted = true;
},),
NB: The DragTarget
is surrounded by a black colored container which is not shown in the code for brevity.
Let’s look at the parameters of the DragTarget
in more detail.
Note: The “data” in the following sections refers to the data parameter of the Draggable
.
Builder
The builder builds the actual widget inside the DragTarget
. This function is called every time a Draggable
is hovered over the DragTarget
or is dropped onto it.
This function has three parameters, context, candidateData and rejectedData.
candidateData is the data of a Draggable
whilst it is hovering over the DragTarget
, ready for acceptance by DragTarget
.
rejectedData is the data of a Draggable
hovering over a DragTarget
at moment it is not accepted.
Note that both of these are dealing with Draggables
which are hovering over the DragTarget
. At this point, they are not dropped onto it yet.
Now, how does the DragTarget
know what to accept?
onWillAccept
onWillAccept
is a function which gives us the Draggable
data for us to decide whether to accept or reject it.
This is where the data we attached onto the Draggable
becomes important. We use the data passed to accept or reject specific Draggables
.
For example if our Draggable is:
Draggable(
data: "Knight",
// ...
),
then we can do:
DragTarget(
// ...
onWillAccept: (data) {
if(data == "Knight") {
return true;
} else {
return false;
}
},
),
This will only accept the Draggable
if the data is “Knight”.
This function is called when the Draggable
is first hovered over the DragTarget
.
onAccept
If the Draggable
is dropped onto the DragTarget
and onWillAccept
returns true, then onAccept
is called.
onAccept
also gives us the data of the Draggable
and is usually used for storing the Draggable
dropped over DragTarget
.
onLeave
This was not implemented in the example. onLeave
is called when a Draggable
is hovered over the DragTarget
and leaves without being dropped.
A Demo
Let’s create a simple demo app where the user is given a number and they are required to sort it as either “even” or “odd’. Depending on the choice, we will then display a message stating whether the choice is correct or wrong.
Source code:
A few more things
Draggable customisations
Draggable
gives us a few more customizations.
One such customization is maxSimultaneousDrags
. Multi-touch devicesare able to drag the same Draggable
with two or more pointers and hence we can have multiple feedback on screen. For instance if the user is using a second finger to drag a child while one drag is already progress, we receive two feedback widgets at the same time.
maxSimultaneousDrags lets us decide the maximum number of times a draggable
can be dragged at one time.
The feedbackOffset
property also lets us set the offset of the feedback widget that displays on the screen.
Common error: DragTarget not accepting data
In the builder function, consider giving a type to the parameter candidateData
. It returns a List
by default, so if the data you’re passing is a string, the type would be List<String>
.
builder: (context, List<String> candidateData, rejectedData) {
// ...
}
This solves a few type errors that occasionally comes up when passing data.
A more complete real-world example using Draggable and DragTarget
Sometime ago, I wrote a complete chessboard package using Draggables
and DragTargets
.
For the complete source code, you can check it out here.
Note: There is an update coming up to the package which includes a better architecture for the package, more boards, etc.
I used the chess_vectors_flutter package for the examples on this article.
A Deep Dive Into Draggable and DragTarget in Flutter的更多相关文章
- Deep Dive into Spark SQL’s Catalyst Optimizer(中英双语)
文章标题 Deep Dive into Spark SQL’s Catalyst Optimizer 作者介绍 Michael Armbrust, Yin Huai, Cheng Liang, Rey ...
- X64 Deep Dive
zhuan http://www.codemachine.com/article_x64deepdive.html X64 Deep Dive This tutorial discusses some ...
- 《Docker Deep Dive》Note - Docker 引擎
<Docker Deep Dive>Note Docker 引擎 1. 概览 graph TB A(Docker client) --- B(daemon) subgraph Docker ...
- 《Docker Deep Dive》Note - 纵观 Docker
<Docker Deep Dive>Note 由于GFW的隔离,国内拉取镜像会报TLS handshake timeout的错误:需要配置 registry-mirrors 为国内源解决这 ...
- Deep Dive into Neo4j 3.5 Full Text Search
In this blog we will go over the Full Text Search capabilities available in the latest major release ...
- 重磅解读:K8s Cluster Autoscaler模块及对应华为云插件Deep Dive
摘要:本文将解密K8s Cluster Autoscaler模块的架构和代码的Deep Dive,及K8s Cluster Autoscaler 华为云插件. 背景信息 基于业务团队(Cloud BU ...
- vue3 deep dive
vue3 deep dive vue core vnode vue core render / mount / patch refs https://www.vuemastery.com/course ...
- Flutter: Draggable和DragTarget 可拖动小部件
API class _MyHomeState extends State<MyHome> { List<Map<String, String>> _data1 = ...
- SQL optimizer -Query Optimizer Deep Dive
refer: http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-1.aspx ...
随机推荐
- 【技术博客】JWT的认证机制Django项目中应用
开发组在开发过程中,都不可避免地遇到了一些困难或问题,但都最终想出办法克服了.我们认为这样的经验是有必要记录下来的,因此就有了[技术博客]. JWT的认证机制Django项目中应用 这篇技术博客基于软 ...
- Tensorflow 损失函数(loss function)及自定义损失函数(三)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/limiyudianzi/article ...
- nodejs中使用cheerio爬取并解析html网页
nodejs中使用cheerio爬取并解析html网页 转 https://www.jianshu.com/p/8e4a83e7c376 cheerio用于node环境,用法与语法都类似于jquery ...
- Jenkins 发布项目到远程服务器上
最近公司弄一个项目,jenkins在本地服务器,需要打包发布到远程的阿里云服务器上,弄了好一阵子. 这里记录下中间的几个坑. 这个Remote DIrectory 很重要,到时候时候会拷贝到这个目录下 ...
- EVE-NG使用手册
转裁于https://www.cnblogs.com/51yuki/articles/eve01.html EVE-NG使用手册 一)EVE-NG的安装 1)下载EVE镜像包 https://pa ...
- WSL记录
cmder(mini版)作为wsl的终端,很好用,可以split屏.但是:千万不要在settings里面设置start up(启动) 里面设置 命令行“bash -cur_console:p1”!目前 ...
- kubernetes 1.9 安装部署
参考地址:https://github.com/gjmzj/kubeasz 引言 提供快速部署高可用k8s集群的工具,基于二进制方式部署和利用ansible-playbook实现自动化,既提供一键安装 ...
- 数据结构各种算法实现(C++模板)
目 录 1.顺序表 1 Seqlist.h 1 Test.cpp 6 2.单链表 8 ListNode.h 8 SingleList.h 10 test.cpp ...
- iOS - 浮点数去掉小数点之后的0,以0.5小数递增函数
NSMutableArray *arrNumber = [NSMutableArray array]; float a = -0.5; ) { a+=0.5; NSString *str = [sel ...
- jsp标签${fn:contains()}遇到问题记录
在jsp页面要实现这样一个功能,列表的某一列字段要显示的数据,是从后台的一个列表中获取的,数据库里面该列存储的方式是 类似 1,2,3 这样的 主键id数据.显示的时候要根据id显示名称,如果是多个 ...