Flutter 拖拽 Draggable DragTarget

在 Flutter 中,实现拖拽功能主要依赖于 DraggableDragTarget 这两个核心组件。Draggable 用于定义可被拖动的"拖拽源",而 DragTarget 用于定义可以接收拖拽元素的"拖拽目标"。

1. Draggable(拖拽源)

Draggable 允许用户通过手势移动组件,并在拖动过程中携带数据。它有几个核心属性:

  • child:正常状态下显示的组件。
  • feedback:拖拽过程中跟随手指移动的组件(通常设置为半透明或带有阴影的副本)。
  • childWhenDragging:拖拽开始后,原位置留下的占位组件(通常设置为灰色或半透明)。也可以不写,这里一般会做半透明效果。
  • data :拖拽时携带的数据,可以是任意类型,传递给 DragTarget
  • axis :限制拖拽方向,可设置为水平(Axis.horizontal)或垂直(Axis.vertical)。不写表示任意方向。

2. DragTarget(拖拽目标)

DragTarget 是接收拖拽元素的区域。当 Draggable 被拖入该区域时,会触发相应的回调。核心属性包括:收到的数据是一个DragTargetDetails对象。里面有offset,data(就是传递过来的参数)

  • builder:构建目标区域的 UI,可以根据当前是否有拖拽元素进入来改变外观6。
  • onWillAcceptWithDetails 废弃的方法是onWillAccept:判断是否接受当前拖拽的数据,返回 true 表示接受。
  • onAcceptWithDetails 废弃的方法onAccept当用户松手且 onWillAcceptWithDetails 返回 true 时触发,处理接收到的数据
scala 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: HomePage()));
}

class HomePage extends StatefulWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  Offset offset = Offset.zero;
  var param = '';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.blue,
        child: Stack(
          children: [
            Positioned(
              left: 100,
              top: 100,
              child: Draggable(
                // 传递给DragTarget的数据
                data: '123',
                // 拖拽过程中显示的组件
                feedback: Container(width: 100, height: 100, color: Colors.red),

                // 正常状态下显示的组件
                childWhenDragging: Container(
                  width: 200,
                  height: 200,
                  color: Colors.red.withValues(alpha: 0.5),
                ),
                onDragUpdate: (DragUpdateDetails details) {
                  setState(() {
                    offset = details.delta;
                  });
                },
                child: Container(width: 200, height: 200, color: Colors.green),
              ),
            ),
            Positioned(
              right: 20,
              bottom: 200,
              width: 200,
              height: 200,
              child: DragTarget(
                builder: (context, candidateData, rejectedData) {
                  return Container(
                    width: 200,
                    height: 200,
                    color: Colors.yellow,
                    child: Text(param),
                  );
                },
                onAcceptWithDetails: (DragTargetDetails data) {
                  setState(() {
                    param = data.data;
                  });
                },
                onWillAcceptWithDetails: (data) {
                  return true;
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class SecondPage extends StatefulWidget {
  SecondPage({Key? key}) : super(key: key);

  @override
  _SecondPageState createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(body: Container(child: null, color: Colors.red));
  }
}
相关推荐
用户2181697049301 小时前
Flutter tootip 轻量级提示
flutter
yume_sibai2 小时前
05-Flutter实战项目
前端·flutter
传奇开心果编程3 小时前
【Flutter入门练中学】第1课:从零开始
学习·flutter·ui
用户21816970493017 小时前
Flutter ClipPath
flutter
用户21816970493020 小时前
Flutter 折叠组件 ExpansionTile ExpansionPanelList
flutter
不羁的木木2 天前
给鸿蒙 App 增加用系统应用打开文件的能力 —— open_app_file 的鸿蒙使用指南
flutter·harmonyos
HouWan2 天前
Flutter: MediaQuery.of(context) 为什么可能拖慢页面?
android·flutter·ios
西西学代码2 天前
flutter---井字游戏
flutter