本文介绍: 2、拖拽两个文件可以合并成一个新的文件夹。1、文件夹可以拖拽到另外一个文件夹中去。4、两个设备可以合并成一个新的文件夹。2、文件夹不可以拖拽到设备中去。3、设备可以拖拽到文件夹中去。1、拖拽文件到文件夹中。
使用LongPressDraggable
和DragTarget
写了个类似于百度云盘管理文件和文件夹的功能(为了避免和列表的滑动手势冲突,所以采用LongPressDraggable
而不是Draggable
):
1、拖拽文件到文件夹中
2、拖拽两个文件可以合并成一个新的文件夹
效果如下:
实现效果
1、文件夹可以拖拽到另外一个文件夹中去
2、文件夹不可以拖拽到设备中去
3、设备可以拖拽到文件夹中去
4、两个设备可以合并成一个新的文件夹
使用到的三方 get: ^4.6.6
代码展示(代码注释都写的比较清楚,如果有不懂的可以在下方留言)
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class DraggableListView extends StatefulWidget {
const DraggableListView({super.key});
@override
State<DraggableListView> createState() => _DraggableListViewState();
}
class _DraggableListViewState extends State<DraggableListView> {
final ScrollController _scrollController = ScrollController();
final TextEditingController _nameController = TextEditingController();
final List<Map<String, dynamic>> _gatherList = [
{'label': '顺义区'},
{'label': '朝阳区'},
{'label': '通州区'},
{'label': '密云区'},
{'label': '海淀区'},
];
final List<Map<String, dynamic>> _deviceList = [
{'label': '设备---1'},
{'label': '设备---2'},
{'label': '设备---3'},
{'label': '设备---4'},
{'label': '设备---5'},
{'label': '设备---6'},
{'label': '设备---7'},
{'label': '设备---8'},
{'label': '设备---9'},
{'label': '设备---10'},
{'label': '设备---11'},
];
///当前拖拽的cell的index
int dragIndex = 0;
///判断拖拽的是文件夹还是设备
bool isDragFile = false;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
_scrollController.dispose();
_nameController.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('DraggableListView'),
),
body: _buildBody(),
);
}
Widget _buildBody() {
Color bgColor = Colors.black38;
return Column(
children: [
Expanded(
child: ListView.builder(
controller: _scrollController,
itemCount: _deviceList.length + _gatherList.length,
itemExtent: cellHeight,
itemBuilder: (context, index) {
///文件夹列表
if (index < _gatherList.length) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 5.0,
),
child: LongPressDraggable(
data: index,
//拖拽的文件夹内容展示
feedback: _buildFeedbackContainer(
index: index,
isFile: true,
),
onDragStarted: () {
dragIndex = index;
isDragFile = true;
},
//被拖拽的文件夹cell在列表中的展示
childWhenDragging: _buildContainerWhenDragging(),
onDragUpdate: (details) {
// 拖拽让列表上下滚动
_scrollListView(details);
},
child: DragTarget<int>(
onAccept: (int data) {
if (!isDragFile) {
///
Get.snackbar("提示",
"${_deviceList[data]}被移动到${_gatherList[index]}中去了");
///如果拖拽的是设备放到文件夹上,就移除设备
_deviceList.removeAt(data);
} else {
///如果拖拽的是文件夹,当拖拽的文件夹和被拖拽的文件夹不是一个的时候,合并文件夹
if (dragIndex != index) {
///
Get.snackbar("提示",
"${_gatherList[data]}被移动到${_gatherList[index]}中去了");
///如果拖拽的是文件夹放到文件夹上,就移除文件夹
_gatherList.removeAt(data);
}
}
setState(() {});
},
onWillAccept: (data) {
if (isDragFile) {
///当拖拽的是某个文件夹的时候,如果拖拽的文件夹放到被拖拽的文件夹上面的时候,不改变原来文件夹的状态(背景色)
if (dragIndex != index) {
bgColor = Colors.red;
}
} else {
bgColor = Colors.red;
}
return data != null;
},
onLeave: (data) {
bgColor = bgColor;
setState(() {});
},
builder: (context, candidateData, rejectedData) {
///文件夹的cell展示
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: bgColor,
borderRadius: const BorderRadius.all(
Radius.circular(18.0),
),
),
child: _buildGatherCell(index),
);
},
),
),
);
}
///设备列表
return Container(
margin: const EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 5.0,
),
child: LongPressDraggable(
data: index - _gatherList.length,
//拖拽的设备内容展示
feedback: _buildFeedbackContainer(
index: index,
isFile: false,
),
//被拖拽的设备cell在列表中的展示
childWhenDragging: _buildContainerWhenDragging(),
onDragStarted: () {
isDragFile = false;
dragIndex = index - _gatherList.length;
},
onDragUpdate: (details) {
// 拖拽让列表上下滚动
_scrollListView(details);
},
child: DragTarget<int>(
onAccept: (int data) {
///拖拽设备放到设备上进行合并+创建新的文件夹
///如果是把文件夹拖拽到设备上不做任何操作
if (!isDragFile) {
_mergeDevice(data: data, index: index);
}
},
onWillAccept: (data) {
if (!isDragFile) {
if (dragIndex != (index - _gatherList.length)) {
bgColor = Colors.red;
}
}
return data != null;
},
onLeave: (data) {
bgColor = bgColor;
setState(() {});
},
builder: (context, candidateData, rejectedData) {
return Container(
alignment: Alignment.center,
color: bgColor,
child: _buildDeviceCell(index),
);
},
),
),
);
},
),
),
],
);
}
///创建文件夹的cell
Widget _buildGatherCell(int index) {
return Row(
children: [
const SizedBox(width: 50.0),
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${_gatherList[index]["label"]}",
style: const TextStyle(
color: Colors.white,
fontSize: 16.0,
),
),
],
),
),
),
const Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
const SizedBox(width: 10.0),
],
);
}
///创建设备的cell
Widget _buildDeviceCell(int index) {
return Row(
children: [
const SizedBox(width: 50.0),
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${_deviceList[index - _gatherList.length]["label"]}",
style: const TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
],
);
}
///合并两个设备-创建新的文件夹
_mergeDevice({
required int data,
required int index,
}) {
Get.defaultDialog(
title: "新建集合",
titlePadding: const EdgeInsets.symmetric(vertical: 16.0),
titleStyle: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w400,
fontSize: 16.0,
),
backgroundColor: const Color.fromRGBO(25, 29, 39, 1),
barrierDismissible: false,
content: Column(
children: [
Container(
height: 44.0,
padding: const EdgeInsets.symmetric(horizontal: 10.0),
margin: const EdgeInsets.symmetric(horizontal: 16.0),
decoration: BoxDecoration(
border: Border.all(
color: const Color.fromRGBO(43, 82, 255, 1),
),
borderRadius: BorderRadius.circular(8.0),
),
alignment: Alignment.center,
child: TextField(
controller: _nameController,
style: const TextStyle(color: Colors.white),
decoration: const InputDecoration(
border: InputBorder.none,
enabledBorder: InputBorder.none,
hintText: "新建集合",
hintStyle: TextStyle(
color: Color.fromRGBO(255, 255, 255, 0.45),
fontSize: 16.0,
),
isCollapsed: true,
// 输入框内容上下居中
contentPadding: EdgeInsets.only(top: 0, bottom: 0),
),
),
),
const SizedBox(height: 20.0),
Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: 105.0,
height: 44.0,
decoration: BoxDecoration(
color: const Color.fromRGBO(2, 3, 6, 1),
borderRadius: BorderRadius.circular(8.0),
),
child: TextButton(
onPressed: () {
_nameController.clear();
setState(() {});
Get.back();
},
child: const Text(
"取消",
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.w400,
),
),
),
),
Container(
width: 105.0,
height: 44.0,
decoration: BoxDecoration(
color: const Color.fromRGBO(43, 82, 255, 1),
borderRadius: BorderRadius.circular(8.0),
),
child: TextButton(
onPressed: () {
if (_nameController.text.isEmpty) {
Get.snackbar("提示", "请输入名称!");
return;
}
for (var item in _gatherList) {
if (item["label"] == _nameController.text) {
Get.snackbar("提示", "该名称已存在,请重新输入!");
return;
}
}
var array = [
_deviceList[data],
_deviceList[index - _gatherList.length]
];
_deviceList
.removeWhere((element) => array.contains(element));
///删除设备之后再创建文件夹
_gatherList.add(
{'label': _nameController.text},
);
var fileName = _nameController.text;
_nameController.clear();
setState(() {});
Get.back();
Get.snackbar(
"提示", "${array[0]}和${array[1]}已合并到文件夹${fileName}中");
},
child: const Text(
"确定",
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.w400,
),
),
),
),
],
),
)
],
),
);
}
///拖拽的时候上下滚动列表
_scrollListView(DragUpdateDetails details) {
if (details.globalPosition.dy < 200) {
if (_scrollController.offset <= 0.0) return;
// 执行向下滚动操作
_scrollController.jumpTo(_scrollController.offset - 5);
}
if (details.globalPosition.dy > 700) {
if (_scrollController.offset >=
_scrollController.position.maxScrollExtent) return;
// 执行向上滚动操作
_scrollController.jumpTo(_scrollController.offset + 5);
}
}
///创建拖拽过程中的内容展示
Widget _buildFeedbackContainer({
required int index,
required bool isFile, //是否是文件夹
}) {
return Container(
alignment: Alignment.center,
width: Get.width,
height: cellHeight,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(10.0),
),
color: Colors.yellow.withOpacity(0.6),
),
child: Text(
isFile
? "拖拽的内容:${_gatherList[index]["label"]}"
: "拖拽的设备:${_deviceList[index - _gatherList.length]["label"]}",
style: const TextStyle(
decoration: TextDecoration.none,
fontSize: 20.0,
color: Colors.red,
),
),
);
}
///创建占位容器
Widget _buildContainerWhenDragging() {
return Container(
alignment: Alignment.center,
color: Colors.red,
child: const Text(
"我是个占位容器,真实的我被拽走了",
style: TextStyle(
color: Colors.black,
),
),
);
}
}
const cellHeight = 88.0;
原文地址:https://blog.csdn.net/weixin_43031192/article/details/136028746
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_66307.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。