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
相關文章
相關標籤/搜索