一统天下 flutter - 输入: Draggable/DragTarget - 拖拽

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

一统天下 flutter - 输入: Draggable/DragTarget - 拖拽

示例如下:

lib\input\drag.dart

/*
 * Draggable/DragTarget - 拖拽
 *
 * Draggable - 按下后可拖拽的对象
 * LongPressDraggable - 长按后可拖拽的对象
 * DragTarget - 拖拽目标,可拖拽对象拖拽到 DragTarget 后可以有交互
 */

import 'package:flutter/material.dart';
import 'package:flutter_demo/helper.dart';

class DragDemo extends StatelessWidget {
  const DragDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('title'),
      ),
      body: Container(
        color: Colors.orange,
        width: double.infinity,
        height: double.infinity,
        child: Stack(
          alignment: Alignment.center,
          children: [
            Positioned(
              top: 10,
              left: 10,
              /// 按下后可拖拽的对象
              child: Draggable(
                /// 传递给 DragTarget 的数据,其类型是泛型 T 也就是说可以传递任意类型的数据
                data: "abc",
                /// 未拖拽时显示的组件
                child: Container(
                  color: Colors.blue,
                  width: 100,
                  height: 100,
                  alignment: Alignment.center,
                  child: const MyTextSmall('未拖拽'),
                ),
                /// 拖拽中时显示的组件
                feedback: Container(
                  color: Colors.red,
                  width: 100,
                  height: 100,
                  alignment: Alignment.center,
                  child: const MyTextSmall('拖拽中'),
                ),
                /// 拖拽中时,初始位置显示的组件
                /// 如果不指定 childWhenDragging 则拖拽中时,初始位置会显示 child
                childWhenDragging: Container(
                  color: Colors.green,
                  width: 100,
                  height: 100,
                  alignment: Alignment.center,
                  child: const MyTextSmall('拖拽中时,初始位置显示的组件'),
                ),

                /// 可拖拽的方向
                /// null - 任意方向
                /// Axis.horizontal - 仅水平方向
                /// Axis.vertical - 仅垂直方向
                axis: null,
                /// 拖拽中时显示的组件与触摸点的行为
                /// pointerDragAnchorStrategy - 拖拽中时显示的组件的左上角的坐标与触摸点的坐标一致
                /// childDragAnchorStrategy - 正常行为
                dragAnchorStrategy: childDragAnchorStrategy,
                /// 最大支持的可同时拖拽的数量
                maxSimultaneousDrags: null,

                /// 开始拖拽时(按下)
                onDragStarted: () {
                  log("onDragStarted");
                },
                /// 拖拽结束时(抬起)
                onDragEnd: (DraggableDetails details) {
                  /// velocity - 用于描述拖拽动作的触摸点的位移速度
                  /// offset - 拖拽动作的触摸点的全局坐标
                  log("onDragEnd velocity:${details.velocity},offset:${details.offset}");
                },
                /// 拖拽结束时(抬起),但是没有在 DragTarget 中释放
                onDraggableCanceled: (Velocity velocity, Offset offset) {
                  /// velocity - 用于描述拖拽动作的触摸点的位移速度
                  /// offset - 拖拽动作的触摸点的全局坐标
                  log('onDraggableCanceled velocity:$velocity,offset:$offset');
                },
                /// 拖拽结束时(抬起),并且在 DragTarget 中释放了
                onDragCompleted: () {
                  log('onDragCompleted');
                },
              ),
            ),

            Positioned(
              top: 10,
              right: 10,
              /// 长按后可拖拽的对象(其他行为和 Draggable 一致,请参见上面关于 Draggable 的说明)
              child: LongPressDraggable(
                /// 传递给 DragTarget 的数据,其类型是泛型 T 也就是说可以传递任意类型的数据
                data: "xyz",
                /// 未拖拽时显示的组件
                child: Container(
                  color: Colors.blue,
                  width: 100,
                  height: 100,
                  alignment: Alignment.center,
                  child: const MyTextSmall('未拖拽'),
                ),
                /// 拖拽中时显示的组件
                feedback: Container(
                  color: Colors.red,
                  width: 100,
                  height: 100,
                  alignment: Alignment.center,
                  child: const MyTextSmall('拖拽中'),
                ),
              ),
            ),

            Positioned(
              /// 拖拽目标,可拖拽对象拖拽到 DragTarget 后可以有交互
              child: DragTarget(
                /// 有 4 种情况会执行到这里
                /// 1、初始时
                /// 2、拖拽动作的触摸点进入时
                /// 3、拖拽动作的触摸点进入后释放时
                /// 4、拖拽动作的触摸点离开时
                builder: (BuildContext context, List<String?> candidateData, List<dynamic> rejectedData) {
                  /// candidateData - 当拖拽动作的触摸点进入时,且 onWillAccept() 返回了 true 则可拖拽对象传来的数据会保存在这里,否则这里是空数据
                  /// rejectedData - 当拖拽动作的触摸点进入时,且 onWillAccept() 返回了 false 则可拖拽对象传来的数据会保存在这里,否则这里是空数据
                  log("candidateData: ${candidateData.isNotEmpty ? candidateData.first : ""}");
                  
                  return Container(
                    color: Colors.blue,
                    width: 100,
                    height: 100,
                    alignment: Alignment.center,
                    child: const MyTextSmall("拖拽目标"),
                  );
                },
                /// 拖拽动作的触摸点进入时,其中的 data 是可拖拽对象传来的数据
                onWillAccept: (data) {
                  log('onWillAccept $data');
                  /// 返回 true 则 data 会保存到 builder 的 candidateData 中
                  /// 返回 false 则 data 会保存到 builder 的 rejectedData 中
                  return true;
                },
                /// 拖拽动作的触摸点进入后释放时,其中的 data 是可拖拽对象传来的数据
                onAccept: (data) {
                  log('onAccept $data');
                },
                /// 拖拽动作的触摸点进入后释放时
                onAcceptWithDetails: (DragTargetDetails<String> details) {
                  /// details.data - 可拖拽对象传来的数据
                  /// details.offset - 拖拽动作的触摸点的全局坐标
                  log('onAcceptWithDetails ${details.data}, ${details.offset}');
                },
                /// 拖拽动作的触摸点离开时,其中的 data 是可拖拽对象传来的数据
                onLeave: (data) {
                  log('onLeave $data');
                },
                /// 拖拽动作的触摸点进入后并移动时
                onMove: (DragTargetDetails<String> details) {
                  /// details.data - 可拖拽对象传来的数据
                  /// details.offset - 拖拽动作的触摸点的全局坐标
                  log('onMove ${details.data}, ${details.offset}');
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

posted @ 2023-04-14 08:49  webabcd  阅读(516)  评论(0编辑  收藏  举报