Flutter 96: 图解 Draggable + DragTarget 基本拖拽效果

简介: 0 基础学习 Flutter,第九十六节:尝试了解基本的拖拽组件!

      小菜尝试做一个新闻类 app 常见的可以滑动添加和删除 item 选项卡的小功能,小菜尝试采用 Draggable + DragTarget 方式;今天先学习一下 Draggable 拖拽组件的基本应用;

Draggable

源码分析

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,
})

      分析源码可得,Draggable 是有状态的 StatefulWidget 组件,一般与 DragTarget 配合使用,拖拽至 DragTarget;其中 childfeedback 是两个必填属性,分别代表默认情况展示的子 Widget 和拖拽过程中移动时的子 Widget

案例尝试

  1. 小菜先尝试一个最基本的 Draggable 效果,然后逐步添加属性效果;
Draggable(
    child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
    feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0));

  1. affinity 属性主要是用于与其他手势竞争,例如在垂直列表中,且 affinity 设置 Axis.horizontal 水平属性,则只允许水平方向拖拽,竖直方向则是列表的滚动;
return ListView(children: <Widget>[
  Icon(Icons.access_alarm, size: 100),
  Icon(Icons.print, size: 100),
  Icon(Icons.android, size: 100),
  Draggable(
      child: Icon(Icons.ac_unit, size: 150, color: Colors.blue),
      feedback: Icon(Icons.ac_unit, size: 200, color: Colors.red),
      affinity: Axis.horizontal),
  Icon(Icons.directions_car, size: 100),
  Icon(Icons.sync, size: 100),
  Icon(Icons.error, size: 100),
  Icon(Icons.send, size: 100),
  Icon(Icons.call, size: 100)
]);

  1. axis 用于限制拖拽方向,水平或竖直方向,若设置 null 则是全方向拖拽;其中在与其他滑动手势冲突时与 affinity 配合使用;
Draggable(affinity: Axis.horizontal, axis: Axis.horizontal,
    child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
    feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0));

  1. childWhenDragging 为拖拽过程中,原位置子 Widget 对应展示内容;
Draggable(affinity: Axis.horizontal, axis: null,
    child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
    feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0),
    childWhenDragging: Image.asset('images/icon_hzw03.jpg', width: 150.0));

  1. dragAnchor 为移动过程中锚点位置,分为 childpointer 两种;child 是以默认子 child 为基础,起始点以 Offset.zero 左上角位置为准;pointer 以在子 child 范围内,手势点击时位置为准;
Draggable(affinity: Axis.horizontal, axis: null,
    child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
    feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0),
    dragAnchor: DragAnchor.pointer);

  1. maxSimultaneousDrags 为针对于同一个子 child 可以同时拖拽个数,小菜尝试的两个手指同时向两个方向拖拽;
Draggable(affinity: Axis.horizontal, axis: null,
    child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
    feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0),
    maxSimultaneousDrags: 2);

  1. ignoringFeedbackSemantics 当子 childfeedback 为同一个 Widget 时,可以通过 ignoringFeedbackSemantics 设为 false 配合 Key 确保是同一个 Widget 减少绘制;
Draggable(affinity: Axis.horizontal, axis: null,
    child: Image.asset('images/icon_hzw01.jpg', width: 150.0, key: _itemKey),
    feedback: Image.asset('images/icon_hzw01.jpg', width: 150.0),
    ignoringFeedbackSemantics: false);
  1. onDraggableX 为拖拽过程中的回调函数;onDragStarted 为开始拖拽时回调;onDraggableCanceled 为在没有被 DragTarget 接收时取消的回调;onDragEnd 为拖拽结束时的回调,不管是否被 DragTarget 接收;onDragCompleted 为被 DragTarget 接收成功时回调;
Draggable(affinity: Axis.horizontal, axis: null,
    child: Image.asset('images/icon_hzw01.jpg', width: 150.0, key: _itemKey),
    feedback: Image.asset('images/icon_hzw01.jpg', width: 150.0),
    childWhenDragging: Container(),
    onDragCompleted: () => print('Draggable --> onDragCompleted'),
    onDragEnd: (DraggableDetails details) => print('Draggable --> onDragEnd --> ${details.offset}'),
    onDraggableCanceled: (Velocity velocity, Offset offset) => print('Draggable --> onDraggableCanceled --> $offset'),
    onDragStarted: () => print('Draggable --> onDragStarted'));

  1. dataT 任意类型数据,主要是向 DragTarget 传递;
data: 'Draggable Data A !!!',

DragTarget

源码分析

const DragTarget({
    Key key,
    @required this.builder,
    this.onWillAccept,
    this.onAccept,
    this.onLeave,
})

      分析源码可得 DragTarget 同样为 StatefulWidget 带状态的 Widget,其中 builder 构造器为必填属性,用于构建接收 Draggable 后的 Widget 构建;

案例尝试

  1. builder 为构造器,其中包括三个属性,分别为 context 上下文环境,candidateDataonWillAccept 回调为 true 时可接收的数据列表,rejectedDataonWillAccept 回调为 false 时拒绝时的数据列表;
          
  2. onWillAccept 为拖拽到 DragTarget 时的回调,true 时会将 Data 数据添加到 candidateData 列表中;false 时会将 Data 数据添加到 rejectedData 列表中;
  3. onAccept 用于接收 Data 数据;
  4. onLeave 为离开时的回调;且小菜测试过程中,当 onWillAccept 返回 true 时,onAcceptonLeave 临界为手势拖拽的最后的坐标是否在 DragTarget 范围内;
          
DragTarget<String>(builder: (BuildContext context, List<String> candidateData, List<dynamic> rejectedData) {
    print('DragTarget --> builder --> $candidateData --> $rejectedData -->$_dragState');
    return _dragState
        ? Image.asset('images/icon_hzw01.jpg', width: 150.0)
        : Container(height: 150.0, width: 150.0, color: Colors.blue.withOpacity(0.4));
  }, onAccept: (String data) {
    print('DragTarget --> onAccept --> $data -->$_dragState');
    setState(() {
      _dragState = true;
    });
  }, onLeave: (String data) {
    print('DragTarget --> onLeave --> $data');
  }, onWillAccept: (String data) {
    print('DragTarget --> onWillAccept --> $data');
    return true;
  });

LongPressDraggable

源码分析

const LongPressDraggable({
    Key key,
    @required Widget child,
    @required Widget feedback,
    T data,
    Axis axis,
    Widget childWhenDragging,
    Offset feedbackOffset = Offset.zero,
    DragAnchor dragAnchor = DragAnchor.child,
    int maxSimultaneousDrags,
    VoidCallback onDragStarted,
    DraggableCanceledCallback onDraggableCanceled,
    DragEndCallback onDragEnd,
    VoidCallback onDragCompleted,
    this.hapticFeedbackOnStart = true,
    bool ignoringFeedbackSemantics = true,
})

      分析源码可得,LongPressDraggable 继承自 Draggable,属性和方法基本完全一致,只是需要长按拖拽;


      Draggable + DragTarget 案例尝试


      小菜简答尝试了 Draggable 拖拽 Widget 以及对应接收拖拽的 DragTarget,下节尝试新闻类类型选项卡;小菜对 Draggable 底层源码还不够熟悉,如有问题请多多指导!

来源: 阿策小和尚

目录
相关文章
|
7月前
|
开发者
Flutter笔记:拖拽手势
Flutter笔记:拖拽手势
91 0
Flutter交互实战-即刻App探索页下拉&拖拽效果
Flutter交互实战-即刻App探索页下拉&拖拽效果
2688 0
|
2月前
|
Android开发 iOS开发 容器
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
|
26天前
|
开发框架 Dart 前端开发
Flutter 是谷歌推出的一款高效跨平台移动应用开发框架,使用 Dart 语言,具备快速开发、跨平台支持、高性能、热重载及美观界面等特点。
Flutter 是谷歌推出的一款高效跨平台移动应用开发框架,使用 Dart 语言,具备快速开发、跨平台支持、高性能、热重载及美观界面等特点。本文从 Flutter 简介、特点、开发环境搭建、应用架构、组件详解、路由管理、状态管理、与原生代码交互、性能优化、应用发布与部署及未来趋势等方面,全面解析 Flutter 技术,助你掌握这一前沿开发工具。
56 8
|
26天前
|
存储 JavaScript 前端开发
在Flutter开发中,状态管理至关重要。随着应用复杂度的提升,有效管理状态成为挑战
在Flutter开发中,状态管理至关重要。随着应用复杂度的提升,有效管理状态成为挑战。本文介绍了几种常用的状态管理框架,如Provider和Redux,分析了它们的基本原理、优缺点及适用场景,并提供了选择框架的建议和使用实例,旨在帮助开发者提高开发效率和应用性能。
34 4
|
26天前
|
传感器 前端开发 Android开发
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求。本文深入探讨了插件开发的基本概念、流程、集成方法、常见类型及开发实例,如相机插件的开发步骤,同时强调了版本兼容性、性能优化等注意事项,并展望了插件开发的未来趋势。
39 2
|
2月前
|
开发者
鸿蒙Flutter实战:07-混合开发
鸿蒙Flutter混合开发支持两种模式:1) 基于har包,便于主项目开发者无需关心Flutter细节,但不支持热重载;2) 基于源码依赖,利于代码维护与热重载,需配置Flutter环境。项目结构包括AppScope、flutter_module等目录,适用于不同开发需求。
103 3
|
1月前
|
传感器 开发框架 物联网
鸿蒙next选择 Flutter 开发跨平台应用的原因
鸿蒙(HarmonyOS)是华为推出的一款旨在实现多设备无缝连接的操作系统。为了实现这一目标,鸿蒙选择了 Flutter 作为主要的跨平台应用开发框架。Flutter 的跨平台能力、高性能、丰富的生态支持和与鸿蒙系统的良好兼容性,使其成为理想的选择。通过 Flutter,开发者可以高效地构建和部署多平台应用,推动鸿蒙生态的快速发展。
228 0