flutter 效果实现 —— 可拖拽 GridView

效果:

代码:

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

  @override
  State<GridDragView> createState() => _GridDragViewState();
}

const List<String> alphas = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'];

class _GridDragViewState extends State<GridDragView> {
  List<String> dataList = List.generate(11, (index) => alphas[index]);

  late List<String> backupDataList;

  bool showSrcElement = false;

  int overlapIndex = -1;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GridView.builder(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
        ),
        itemCount: dataList.length,
        itemBuilder: (context, index) => _buildItem(index, dataList[index]),
      ),
    );
  }

  Widget _buildItem(index, myData) {
    return Draggable<String>(
      data: myData,
      child: DragTarget<String>(
        builder: (context, candidateData, rejectedData) {
          var myIndex = dataList.indexOf(myData);
          return myIndex == overlapIndex
              ? SizedBox.shrink()
              : Card(
                  child: Center(
                    child: Text("x = $myData"),
                  ),
                );
        },
        //松手时如果onWillAccept返回true时触发调用
        onAccept: (data) {
          // setState(() {
          //   overlapIndex = -1;
          // });
        },
        //手指拖着一个widget从另一个widget头上滑走时触发调用
        onLeave: (data) {
          print('$data is Leaving item $myData');
          setState(() {
            overlapIndex = -1;
            showSrcElement = false;
            dataList = [...backupDataList];
          });
        },
        //移动到目标组件时触发调用
        //返回值是接下来松手 是否需要将数据给这个widget?
        onWillAccept: (data) {
          print('index: $index');
          print('$myData will accept item $data');
          if (data != null && data != myData) {
            //目标位置留空
            //原位置移除(由前后位置自动占位)
            setState(() {
              var draggingIndex = backupDataList.indexOf(data);
              var myIndex = backupDataList.indexOf(myData);
              print('draggingIndex: $draggingIndex');
              print('myIndex: $myIndex');
              dataList.removeAt(draggingIndex);
              dataList.insert(index, data);
              showSrcElement = true;
              overlapIndex = index;
            });
          }
          return true;
        },
      ),
      //拖动事件
      onDragStarted: () {
        //开始拖动,备份数据源
        print('item $myData ---------------------------onDragStarted');
        backupDataList = [...dataList];
      },
      onDraggableCanceled: (Velocity velocity, Offset offset) {
        print(
            'item $myData ---------------------------onDraggableCanceled,velocity = $velocity,offset = $offset');
        //拖动取消,还原数据源
        setState(() {
          overlapIndex = -1;
          showSrcElement = false;
          dataList = [...backupDataList];
        });
      },
      onDragCompleted: () {
        //拖动完成,刷新状态
        print("item $myData ---------------------------onDragCompleted");
        setState(() {
          showSrcElement = false;
          overlapIndex = -1;
        });
      },
      //拖动时的组件
      feedback: Card(
        child: Padding(
          padding: EdgeInsets.symmetric(horizontal: 50.0, vertical: 50.0),
          child: Center(
            child: Text("x = $myData"),
          ),
        ),
      ),
      //被拖动的组件的最初位置
      childWhenDragging: showSrcElement
          ? Card(
              child: Padding(
                padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 50.0),
                child: Center(
                  child: Text("x = $myData"),
                ),
              ),
            )
          : SizedBox.shrink(),
    );
  }
}

posted on 2022-09-05 22:38  Lemo_wd  阅读(922)  评论(0编辑  收藏  举报

导航