美文网首页Flutter UI
flutter-父子list的item拖动排序与合并

flutter-父子list的item拖动排序与合并

作者: Small寻 | 来源:发表于2021-03-07 15:39 被阅读0次

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/b08e210b8a38https://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(() {

      });
    }
  }
}

相关文章

网友评论

    本文标题:flutter-父子list的item拖动排序与合并

    本文链接:https://www.haomeiwen.com/subject/mklyqltx.html