flutter多list拖动排序
背景
最近工作中开始从Android转到flutter,产品经理提了这样一个需求,
有2个list,每一个list都可以通过长按来拖动,重新排序里面item,同时还可以通过长按拖动操作将子item的内容填充到父list中,实现结果就是如下面这个gif所示,
list.gif我从网上找了很多关于拖动排序的文章,发现几乎都是单个listview拖动排序的内容,用的就是插件ReorderableListView,我自己也实现了一个ReorderableListView来,发现它用于单个list拖动排序十分好用,但是如果是我遇到的2个list就无能为力了。网上也没有找到2个list拖动排序的内容,经过我自己对控件DragTarget和Draggable的学习,自己实现了一套2个list拖动的排序的代码,写下这篇文章来记录一下,如果有遇到同样问题的小伙伴可以参考一下。
先放上我借鉴的关于ReorderableListView,DragTarget和Draggable的文章链接,感谢他们的分享
ReorderableListView的 RecorderableListView https://www.cnblogs.com/mengqd/p/12437190.html
DragTarget和Draggable https://www.jianshu.com/p/b08e210b8a38,https://www.jianshu.com/p/bf8ea911a1c4
代码
放上我写的主要的代码,
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class TwoListDragSortPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _TwoListDragSortState();
}
}
class _TwoListDragSortState extends State<TwoListDragSortPage> {
//伪造的数据,只是用于展示
//其中每一个list中都有一个最后一个空值,用于拖动能够拖动到最后一项
List leftList = ["数字", "汉字", "字母", "混合", ""];
List<List> rightList = [
["1", "2", "3", "4", ""],
["发", "方式", "嘎阿尔", "人情味", ""],
["a", "b", "c", "d", ""],
["faga", "frety", "bnsh", "tqwv", ""]
];
int chooseIndex = 0;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("双list排序"),
),
body: Container(
child: Row(
children: [
Flexible(
flex: 2,
child: ListView.separated(
itemBuilder: (context, index) {
return _getLeftWidget(index);
},
separatorBuilder: (context, index) {
if (index < leftList.length - 1) {
return Divider(
height: 1,
color: Colors.black87,
);
} else {
return Container();
}
},
itemCount: leftList.length)),
VerticalDivider(width: 2,color: Colors.white,),
Flexible(
flex: 5,
child: ListView.separated(
itemBuilder: (context, index) {
return _getRightWidget(index);
},
separatorBuilder: (context, index) {
if (index < rightList[chooseIndex].length - 1) {
return Divider(
height: 1,
color: Colors.black12,
);
} else {
return Container();
}
},
itemCount: rightList[chooseIndex].length)),
],
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Widget _getLeftItem(int index, bool isdrag) {
//list最后有一个空的item,是为了能够插入到最后一项目
if(index<leftList.length-1) {
return Container(
height: 30,
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 5),
color: isdrag
? Colors.black12
: index == chooseIndex
? Colors.orangeAccent
: Colors.black45,
child: Text(
leftList[index],
style: TextStyle(color: Colors.white, fontSize: 15),
),
);
}else{
return Container(
height: 30,
);
}
}
Widget _getLeftWidget(int index) {
//父list的每一个item是一个DragTarget可以接受数据
//也是一个LongPressDraggable可以被拖动
//同时也要有一个可以点击选中的状态
return InkWell(
onTap: () {
setState(() {
if (chooseIndex != index) {
chooseIndex = index;
}
});
},
child: DragTarget(
builder: (BuildContext context, List<String> candidateData,
List<dynamic> rejectedData) {
if (candidateData.isNotEmpty && candidateData.first == 'aa') {
} else if (rejectedData.isNotEmpty) {
} else {}
return LongPressDraggable(
data: "${index}",
child: _getLeftItem(index, false), //默认子控件状态
feedback: _getLeftItem(index, true),//拖动时,拖动的状态
childWhenDragging: Container(), //拖动时,子控件的状态
);
},
onWillAccept: (s) {
return true;
},
onAccept: (s) {
//判断接受的数据,是子list拖动进入父list,还是父list自身排序
List list = (s as String).split("_");
if (list.length == 1) {
int newIndex = index;
int cuIndex = int.parse(list[0]);
moveLeftToleft(cuIndex, newIndex);
} else if (list.length == 2) {
int leftIndex = index;
int rightIndex = int.parse(list[1]);
moveRightToleft(leftIndex, rightIndex);
}
},
onAcceptWithDetails: (DragTargetDetails<String> details) {
},
onLeave: (s) {
},
onMove: (DragTargetDetails<dynamic> details) {
},
),
);
}
Widget _getRigthItem(int index, bool isDrag) {
//list最后有一个空的item,是为了能够插入到最后一项目
if(index<rightList[chooseIndex].length-1){
return Container(
height: 50,
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 5, right: 5),
color: isDrag ? Colors.black12 : Colors.black45,
child: Text(
rightList[chooseIndex][index],
style: TextStyle(color: Colors.white, fontSize: 35),
),
);
}
else{
return Container(
height: 50,
);
}
}
Widget _getRightWidget(int index) {
//子list的每一个item是一个DragTarget可以接受数据
//也是一个LongPressDraggable可以被拖动
return DragTarget(
builder: (BuildContext context, List<String> candidateData,
List<dynamic> rejectedData) {
if (candidateData.isNotEmpty) {
} else if (rejectedData.isNotEmpty) {
} else {}
return LongPressDraggable(
//这个地方,data我自己也有疑问,之前尝试过用list,
//发现接受不到list的数据,只能用String来表示是子list还是父list的item被拖动了
data: "${chooseIndex}_${index}",
child: _getRigthItem(index, false),
feedback: _getRigthItem(index, true),
childWhenDragging: Container(),
);
},
onWillAccept: (s) {
//判断接受的数据,只能接受子list中拖动排序
List list = (s as String).split("_");
if (list.length == 2) {
return true;
}
return false;
},
onAccept: (s) {
//只有onWillAccept返回值为true的时候才能接受到的数据
List list = (s as String).split("_");
if (list.length == 2) {
int newIndex = index;
int cuIndex = int.parse(list[1]);
moveRightToRight(cuIndex, newIndex);
}
},
onAcceptWithDetails: (DragTargetDetails<String> details) {
},
onLeave: (s) {
},
onMove: (DragTargetDetails<dynamic> details) {
},
);
}
/**
* 父list的拖动排序
*/
void moveLeftToleft(int cuIndex,int newIndex){
if(cuIndex!=newIndex){
String str = leftList[cuIndex];
List list = rightList[cuIndex];
rightList.removeAt(cuIndex);
leftList.removeAt(cuIndex);
//根据拖动的位置,重新确定父list的数据
if(newIndex<cuIndex){
leftList.insert(newIndex, str);
rightList.insert(newIndex, list);
}else{
leftList.insert(newIndex-1 , str);
rightList.insert(newIndex - 1, list);
}
//由于拖动的关系,父list的选中状态要重新结算位置
if(cuIndex==chooseIndex){
if(newIndex<cuIndex){
chooseIndex = newIndex;
}else{
chooseIndex = newIndex - 1;
}
}
else if(chooseIndex>cuIndex&&chooseIndex<newIndex){
chooseIndex -= 1;
}
else if(chooseIndex>newIndex&&chooseIndex<cuIndex){
chooseIndex += 1;
}
setState(() {
});
}
}
/**
* 子list的item拖动进入父list
*/
void moveRightToleft(int leftIndex,int rightIndex){
String str = rightList[chooseIndex][rightIndex];
rightList[chooseIndex].removeAt(rightIndex);
rightList[leftIndex].insert(rightList[leftIndex].length-1, str);
//如果某一个子list中的的item被移除完了,要删除它的父item
if(rightList[chooseIndex].length==1){
leftList.removeAt(chooseIndex);
chooseIndex = leftIndex;
}
setState(() {
});
}
/**
* 子list自己拖动排序
*/
void moveRightToRight(int cuIndex,int newIndex){
if(cuIndex!=newIndex){
String str = rightList[chooseIndex][cuIndex];
rightList[chooseIndex].removeAt(cuIndex);
if(newIndex<cuIndex){
rightList[chooseIndex].insert(newIndex, str);
}else{
rightList[chooseIndex].insert(newIndex-1, str);
}
setState(() {
});
}
}
}
网友评论