Flutter 交互基础之 Draggable

介绍

Draggable 是Flutter中的一个能够拖拽到DragTarget的Widget。而且,他能够把本身携带的数据传递给DragTarget。当Draggable被拖动到DragTarget的时候,DragTarget会判断是否是须要接收传递过来的数据,在接收后作相应的状态改变。java

继承关系

Object -> Diagnosticable -> DiagnosticableTree -> Widget ->StatefulWidget -> Draggablegit

构造函数

Draggable({Key key, 
 @required Widget child,
 @required Widget feedback,
 T data, 
 Axis axis,
 Widget childWhenDragging,
 Offset feedbackOffset: Offset.zero, 
 DragAnchor dragAnchor: DragAnchor.child, 
 Axis affinity, 
 int maxSimultaneousDrags,
 VoidCallback onDragStarted, 
 DraggableCanceledCallback onDraggableCanceled, 
 DragEndCallback onDragEnd, 
 VoidCallback onDragCompleted, 
 bool ignoringFeedbackSemantics: true }) 
复制代码

经常使用属性

  • affinity → Axis 控制此窗口小部件如何与其余手势竞争以启动拖动。
  • axis → Axis 限制此可拖动移动的轴(若是有指定)。
  • child → Widget 子控件。
  • childWhenDragging → Widget 当一个或多个拖动操做正在进行时,所要显示的控件而不是子控件。
  • data → T 表示要传入DragTarget 的数据。
  • dragAnchor → DragAnchor 在拖动过程当中,所应该指定此Widget的位置。
  • feedback → Widget 当拖动正在进行时,指定在当前Point下所显示的Widget。
  • feedbackOffset → Offset feedbackOffset可用于设置命中测试目标点,以便找到拖动的目标。若是将反馈与子控件相比进行转换,则尤为有用。
  • ignoringFeedbackSemantics → bool 构建语义树的时候,是否忽略反馈Widget的语义。
  • maxSimultaneousDrags → int 最大支持多少个同时拖动的Widget。
  • onDragCompleted → VoidCallback 当Draggable被DraggTarget移除并接受时调用,表示拖拽完成。
  • onDragEnd → DragEndCallback 当Draggable被DraggTarget移除时调用。
  • onDraggableCanceled → DraggableCanceledCallback 当Draggable被DraggTarget移除时而且不被接受时调用,表示拖拽被取消。
  • onDragStarted → VoidCallback 当 draggable 开始被拖拽时调用。

经常使用方法

  • createRecognizer(GestureMultiDragStartCallback onStart) → 建立一个识别拖动开始的手势识别器。
  • createState() → _DraggableState 在树中的给定位置为此Widget建立可变状态。

使用示例

示例1:github

draggable.gif

代码以下:bash

import 'package:flutter/material.dart';

class DraggableTest extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return DraggableState();
  }
}

class DraggableState extends State<DraggableTest> {
  Offset _offset = Offset(100, 100);
  double _width = 120.0;
  String url =
      "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564055541946&di=6da25e7ef3c905ce81d5e75694b62c19&imgtype=0&src=http%3A%2F%2Fimg4q.duitang.com%2Fuploads%2Fitem%2F201407%2F02%2F20140702203112_BGFPv.thumb.700_0.jpeg";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("DraggableDemo"),
        ),
        body: Transform.translate(
            offset: _offset,
            child: Draggable(
              child: Image.network(url, width: _width),
              feedback: Image.network(url, width: _width),
              childWhenDragging: Image.network(url, width: _width),
              onDraggableCanceled: (v, o) {
                setState(() {
                  _offset = o;
                  print("dx:" + o.dx.toString());
                  print("dy:" + o.dy.toString());
                });
              },
              onDragCompleted: () {
                print("onDragCompleted");
              },
              onDragEnd: (dragEndDetails) {
                setState(() {
                  _offset = dragEndDetails.offset;
                });
                print("onDragEnd");
                print(" dragEndDetails.offset:" +
                    dragEndDetails.offset.toString());
              },
            )));
  }
}

复制代码

除此以外,咱们也能够修改一下代码,childWhenDragging参数传入一个不可见的Widget,用于实现相似于GestureDetector 的拖拽平移功能。app

示例2:ide

draggable2.gif

代码以下:函数

import 'package:flutter/material.dart';

class DraggableTest extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return DraggableState();
  }
}

class DraggableState extends State<DraggableTest> {
  Offset _offset = Offset(100, 100);
  double _size = 150.0;
  String url =
      "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564055541946&di=6da25e7ef3c905ce81d5e75694b62c19&imgtype=0&src=http%3A%2F%2Fimg4q.duitang.com%2Fuploads%2Fitem%2F201407%2F02%2F20140702203112_BGFPv.thumb.700_0.jpeg";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("DraggableDemo"),
        ),
        body: Transform.translate(
            offset: _offset,
            child: Draggable(
              child: Image.network(url, width: _size),
              feedback: Image.network(url, width: _size),
              childWhenDragging: Container(
                width: 0,
                height: 0,
              ),
              onDragEnd: (dragEndDetails) {
                setState(() {
                  _offset = dragEndDetails.offset;
                  print(" onDragEnd - dragEndDetails.offset:" +
                      dragEndDetails.offset.toString());
                });
              },
            )));
  }
}

复制代码

log 输出测试

2019-08-09 17:01:18.492 15029-15061/com.xiaosong.flutterwidgets I/flutter: onDragStarted
2019-08-09 17:01:20.091 15029-15061/com.xiaosong.flutterwidgets I/flutter:  onDragEnd - dragEndDetails.offset:Offset(57.7, 370.0)
2019-08-09 17:01:20.091 15029-15061/com.xiaosong.flutterwidgets I/flutter: dx:57.66666666666674, dy:370.0000000000001
2019-08-09 17:01:23.385 15029-15061/com.xiaosong.flutterwidgets I/flutter: onDragStarted
2019-08-09 17:01:23.878 15029-15061/com.xiaosong.flutterwidgets I/flutter:  onDragEnd - dragEndDetails.offset:Offset(114.0, 274.3)
2019-08-09 17:01:23.878 15029-15061/com.xiaosong.flutterwidgets I/flutter: dx:114.00000000000007, dy:274.3333333333334
复制代码

从log 能够看到,若是没有与DragTarget 配合使用,它不会触发 onDragCompleted 或者 onDraggableCanceled 回调。而onDragStarted、onDragEnd 依旧会触发。ui

总结

本篇文章咱们大体讲解了Draggable的基本概念及经常使用示例。因为Draggable 没有 GestureDetector中相似onPanUpdate的监听,所以触发onDragEnd 的position 并非很是精准。若咱们须要拖拽平移Widget,通常来讲仍是建议经过GestureDetector去实现,Draggable通常是搭配DragTarget去使用的。下篇文章咱们将讲解如何搭配DragTarget来实现拖拽状态并改变数据。url

做者


xiaosongzeem
相关文章
相关标签/搜索