Flutter可重排序列表插件vietmap_reorderable_list的使用

Flutter可重排序列表插件vietmap_reorderable_list的使用

一个简单的包用于创建可重排序的列表。

示例代码

import 'package:flutter/material.dart' hide ReorderableListView;
import 'package:intl/intl.dart';
import 'package:vietmap_reorderable_list/widgets/vietmap_reorderable_list.dart';

void main() => runApp(const ReorderableApp());

class ReorderableApp extends StatelessWidget {
  const ReorderableApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('可重排序列表示例')),
        body: const ReorderableExample(),
      ),
    );
  }
}

class MockData {
  final String name;

  final int timeStamp;
  MockData({required this.name, required this.timeStamp});
}

class ReorderableExample extends StatefulWidget {
  const ReorderableExample({super.key});

  @override
  State<ReorderableExample> createState() => _ReorderableListViewExampleState();
}

class _ReorderableListViewExampleState extends State<ReorderableExample> {
  final List<int> _items = List<int>.generate(50, (int index) => index);
  List<GlobalKey> itemKeys = [];
  ScrollController scrollController = ScrollController();
  final List<MockData> data = [
    MockData(name: '项目 1', timeStamp: 1710992339000),
    MockData(name: '项目 2', timeStamp: 1710993339000),
    MockData(name: '项目 3', timeStamp: 1710994339000),
    MockData(name: '项目 4', timeStamp: 1710995339000),
    MockData(name: '项目 5', timeStamp: 1710996339000),
    MockData(name: '项目 6', timeStamp: 1710997339000),
    MockData(name: '项目 7', timeStamp: 1710998339000),
    MockData(name: '项目 8', timeStamp: 1710999339000),
    MockData(name: '项目 9', timeStamp: 1711000339000),
    MockData(name: '项目 10', timeStamp: 1711001339000),
    MockData(name: '项目 11', timeStamp: 1711002339000),
    MockData(name: '项目 12', timeStamp: 1711003339000),
    MockData(name: '项目 13', timeStamp: 1711004339000),
    MockData(name: '项目 14', timeStamp: 1711005339000),
    MockData(name: '项目 15', timeStamp: 1711006339000),
    MockData(name: '项目 16', timeStamp: 1711007339000),
    MockData(name: '项目 17', timeStamp: 1711008339000),
    MockData(name: '项目 18', timeStamp: 1711009339000),
    MockData(name: '项目 19', timeStamp: 1711010339000),
    MockData(name: '项目 20', timeStamp: 1711011339000),
    MockData(name: '项目 21', timeStamp: 1711012339000),
    MockData(name: '项目 22', timeStamp: 1711013339000),
    MockData(name: '项目 23', timeStamp: 1711014339000),
    MockData(name: '项目 24', timeStamp: 1711015339000),
    MockData(name: '项目 25', timeStamp: 1711016339000),
    MockData(name: '项目 26', timeStamp: 1711017339000),
    MockData(name: '项目 27', timeStamp: 1711018339000),
    MockData(name: '项目 28', timeStamp: 1711019339000),
    MockData(name: '项目 29', timeStamp: 1711020339000),
    MockData(name: '项目 30', timeStamp: 1711021339000),
    MockData(name: '项目 31', timeStamp: 1711022339000),
    MockData(name: '项目 32', timeStamp: 1711023339000),
    MockData(name: '项目 33', timeStamp: 1711024339000),
    MockData(name: '项目 34', timeStamp: 1711025339000),
    MockData(name: '项目 35', timeStamp: 1711026339000),
    MockData(name: '项目 36', timeStamp: 1711027339000),
    MockData(name: '项目 37', timeStamp: 1711028339000),
    MockData(name: '项目 38', timeStamp: 1711029339000),
    MockData(name: '项目 39', timeStamp: 1711030339000),
    MockData(name: '项目 40', timeStamp: 1711031339000),
    MockData(name: '项目 41', timeStamp: 1711032339000),
    MockData(name: '项目 42', timeStamp: 1711033339000),
    MockData(name: '项目 43', timeStamp: 1711034339000),
    MockData(name: '项目 44', timeStamp: 1711035339000),
    MockData(name: '项目 45', timeStamp: 1711036339000),
    MockData(name: '项目 46', timeStamp: 1711037339000),
    MockData(name: '项目 47', timeStamp: 1711038339000),
    MockData(name: '项目 48', timeStamp: 1711039339000),
    MockData(name: '项目 49', timeStamp: 1711040339000),
    MockData(name: '项目 50', timeStamp: 1711041339000),
  ];

  @override
  void initState() {
    scrollController.addListener(() {
      // print('+++++++++++++++++++++++++++++++++++++++++');
      // print(scrollController.position.pixels);
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final ColorScheme colorScheme = Theme.of(context).colorScheme;
    final Color oddItemColor = colorScheme.primary.withOpacity(0.05);
    final Color evenItemColor = colorScheme.primary.withOpacity(0.15);

    return Container(
      color: Colors.red.withOpacity(0.2),
      child: Stack(
        children: [
          Positioned(
            top: 0,
            left: 95,
            child: Container(
              width: 5,
              height: MediaQuery.sizeOf(context).height,
              color: Colors.red,
            ),
          ),
          VietmapReorderableListView(
            scrollController: scrollController,
            padding: const EdgeInsets.symmetric(horizontal: 40),
            onReorderStart: (index) {
              // print('-----------------zzz');
            },
            children: List.generate(50, (index) {
              itemKeys.add(GlobalKey());
              return Listener(
                onPointerMove: (event) {
                  // print(event.position.dy);
                  // print('-----------------Pointer Move-----------------');
                },
                key: itemKeys[index],
                // onVerticalDragUpdate: (details) {
                //   print('---------------d-----------------');
                // },
                child: ListTile(
                  contentPadding: EdgeInsets.zero,
                  tileColor: Colors.transparent,
                  leading: Text(formatTime(data[index].timeStamp)),
                  title: Container(
                      padding: const EdgeInsets.symmetric(
                          horizontal: 10, vertical: 15),
                      decoration: BoxDecoration(
                        color:
                            _items[index].isOdd ? oddItemColor : evenItemColor,
                      ),
                      child: Text('项目 ${_items[index]}')),
                ),
              );
            }),
            onReordering: (index, dragIndex) {
              print('-----------------reordering$index, $dragIndex');

              MockData nearestTopData = data[dragIndex - 2];
              MockData currentData = data[dragIndex - 1];
              MockData nearestBottomData = data[dragIndex];
              // print(nearestTopData.name);
              // print(currentData.name);
              // print(nearestBottomData.name);
              // print('----------------------------------');
              // print(_getPosition(dragIndex - 2));
              // print(_getPosition(dragIndex - 1));
              // print(_getPosition(dragIndex));
              // print('--------------------enda--------------');
              // print(nearestTopData.timeStamp);

              // print(nearestBottomData.timeStamp);
            },
            onReorderEnd: (index) {
              // print('-----------------end');
            },
            onReorder: (int oldIndex, int newIndex) {
              setState(() {
                if (oldIndex < newIndex) {
                  newIndex -= 1;
                }
                final int item = _items.removeAt(oldIndex);
                _items.insert(newIndex, item);
                data.insert(newIndex, data.removeAt(oldIndex));
              });
            },
          ),
        ],
      ),
    );
  }

  double _getPosition(int index) {
    RenderBox box =
        itemKeys[index].currentContext!.findRenderObject() as RenderBox;
    Offset currentPosition =
        box.localToGlobal(Offset.zero); //this is global position
    double y = currentPosition.dy; //this is y - I think it's what you want
    return y;
  }

  String formatTime(int timeStamp) {
    return DateFormat('HH:mm aa')
        .format(DateTime.fromMillisecondsSinceEpoch(timeStamp));
  }
}

代码解释

  1. 导入必要的库

    import 'package:flutter/material.dart' hide ReorderableListView;
    import 'package:intl/intl.dart';
    import 'package:vietmap_reorderable_list/widgets/vietmap_reorderable_list.dart';
    
  2. 定义主应用类 ReorderableApp

    class ReorderableApp extends StatelessWidget {
      const ReorderableApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(title: const Text('可重排序列表示例')),
            body: const ReorderableExample(),
          ),
        );
      }
    }
    
  3. 定义数据模型 MockData

    class MockData {
      final String name;
      final int timeStamp;
      MockData({required this.name, required this.timeStamp});
    }
    
  4. 定义状态管理类 _ReorderableListViewExampleState

    class _ReorderableListViewExampleState extends State<ReorderableExample> {
      final List<int> _items = List<int>.generate(50, (int index) => index);
      List<GlobalKey> itemKeys = [];
      ScrollController scrollController = ScrollController();
      final List<MockData> data = [
        // 数据项
      ];
    
  5. 初始化状态并监听滚动事件

    @override
    void initState() {
      scrollController.addListener(() {
        // print('+++++++++++++++++++++++++++++++++++++++++');
        // print(scrollController.position.pixels);
      });
      super.initState();
    }
    
  6. 构建UI

    @override
    Widget build(BuildContext context) {
      final ColorScheme colorScheme = Theme.of(context).colorScheme;
      final Color oddItemColor = colorScheme.primary.withOpacity(0.05);
      final Color evenItemColor = colorScheme.primary.withOpacity(0.15);
    
      return Container(
        color: Colors.red.withOpacity(0.2),
        child: Stack(
          children: [
            Positioned(
              top: 0,
              left: 95,
              child: Container(
                width: 5,
                height: MediaQuery.sizeOf(context).height,
                color: Colors.red,
              ),
            ),
            VietmapReorderableListView(
              scrollController: scrollController,
              padding: const EdgeInsets.symmetric(horizontal: 40),
              onReorderStart: (index) {
                // print('-----------------zzz');
              },
              children: List.generate(50, (index) {
                itemKeys.add(GlobalKey());
                return Listener(
                  onPointerMove: (event) {
                    // print(event.position.dy);
                    // print('-----------------Pointer Move-----------------');
                  },
                  key: itemKeys[index],
                  child: ListTile(
                    contentPadding: EdgeInsets.zero,
                    tileColor: Colors.transparent,
                    leading: Text(formatTime(data[index].timeStamp)),
                    title: Container(
                        padding: const EdgeInsets.symmetric(
                            horizontal: 10, vertical: 15),
                        decoration: BoxDecoration(
                          color: _items[index].isOdd ? oddItemColor : evenItemColor,
                        ),
                        child: Text('项目 ${_items[index]}')),
                  ),
                );
              }),
              onReordering: (index, dragIndex) {
                print('-----------------reordering$index, $dragIndex');
                // 处理重新排序逻辑
              },
              onReorderEnd: (index) {
                // print('-----------------end');
              },
              onReorder: (int oldIndex, int newIndex) {
                setState(() {
                  if (oldIndex < newIndex) {
                    newIndex -= 1;
                  }
                  final int item = _items.removeAt(oldIndex);
                  _items.insert(newIndex, item);
                  data.insert(newIndex, data.removeAt(oldIndex));
                });
              },
            ),
          ],
        ),
      );
    }
    
  7. 获取元素位置

    double _getPosition(int index) {
      RenderBox box =
          itemKeys[index].currentContext!.findRenderObject() as RenderBox;
      Offset currentPosition =
          box.localToGlobal(Offset.zero); //this is global position
      double y = currentPosition.dy; //this is y - I think it's what you want
      return y;
    }
    
  8. 格式化时间戳

    String formatTime(int timeStamp) {
      return DateFormat('HH:mm aa')
          .format(DateTime.fromMillisecondsSinceEpoch(timeStamp));
    }
    

更多关于Flutter可重排序列表插件vietmap_reorderable_list的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter可重排序列表插件vietmap_reorderable_list的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


vietmap_reorderable_list 是一个用于 Flutter 的可重排序列表插件,它允许用户通过拖拽来重新排序列表中的项目。这个插件非常适合需要用户自定义列表顺序的应用场景。

安装

首先,你需要在 pubspec.yaml 文件中添加依赖:

dependencies:
  vietmap_reorderable_list: ^1.0.0

然后运行 flutter pub get 来安装插件。

基本用法

下面是一个简单的示例,展示了如何使用 vietmap_reorderable_list 来创建一个可重排序的列表。

import 'package:flutter/material.dart';
import 'package:vietmap_reorderable_list/vietmap_reorderable_list.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ReorderableListExample(),
    );
  }
}

class ReorderableListExample extends StatefulWidget {
  @override
  _ReorderableListExampleState createState() => _ReorderableListExampleState();
}

class _ReorderableListExampleState extends State<ReorderableListExample> {
  List<String> items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Reorderable List Example'),
      ),
      body: VietMapReorderableList(
        children: items.map((item) {
          return ListTile(
            key: Key(item),
            title: Text(item),
          );
        }).toList(),
        onReorder: (oldIndex, newIndex) {
          setState(() {
            if (newIndex > oldIndex) {
              newIndex -= 1;
            }
            final item = items.removeAt(oldIndex);
            items.insert(newIndex, item);
          });
        },
      ),
    );
  }
}

代码解释

  1. 依赖导入:首先导入 vietmap_reorderable_list 插件。

  2. 状态管理:使用 StatefulWidget 来管理列表的状态。items 是一个字符串列表,表示列表中的项目。

  3. VietMapReorderableList 组件:这是一个核心组件,用于创建可重排序的列表。它接受两个主要参数:

    • children:列表中的项目,通常是一个 List<Widget>
    • onReorder:当用户拖拽项目并重新排序时触发的回调函数。oldIndex 是项目原来的位置,newIndex 是项目将要移动到的位置。
  4. onReorder 回调:在 onReorder 回调中,我们更新 items 列表的顺序。首先,我们根据 oldIndexnewIndex 调整项目的顺序,然后调用 setState 来更新 UI。

自定义样式

你可以根据需要自定义列表项的样式。例如,可以给 ListTile 添加图标、背景颜色等。

ListTile(
  key: Key(item),
  title: Text(item),
  leading: Icon(Icons.drag_handle),
  tileColor: Colors.grey[200],
)
回到顶部