Flutter列表重排序插件flutter_reorderable_list的使用

发布于 1周前 作者 gougou168 来自 Flutter

Flutter列表重排序插件 flutter_reorderable_list 的使用

flutter_reorderable_list 是一个类似于 iOS 的可重排列表插件,支持平滑的动画效果,并且可以在 CustomScrollView 中与 SliverAppBar 一起使用。本文将详细介绍如何使用这个插件,并提供完整的示例代码。

预览

Preview

开始使用

要开始使用 flutter_reorderable_list 插件,请参考以下示例代码。你可以直接在你的项目中复制并修改这些代码以适应你的需求。

安装插件

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

dependencies:
  flutter_reorderable_list: ^0.4.3

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

示例代码

以下是一个完整的示例,展示了如何使用 flutter_reorderable_list 插件来创建一个可重排的列表。

import 'package:flutter/material.dart' hide ReorderableList;
import 'package:flutter_reorderable_list/flutter_reorderable_list.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Reorderable List',
      theme: ThemeData(
        dividerColor: const Color(0x50000000),
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Reorderable List'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class ItemData {
  ItemData(this.title, this.key);

  final String title;
  final Key key;
}

enum DraggingMode {
  iOS,
  android,
}

class _MyHomePageState extends State<MyHomePage> {
  late List<ItemData> _items;

  _MyHomePageState() {
    _items = [];
    for (int i = 0; i < 500; ++i) {
      String label = "List item $i";
      if (i == 5) {
        label += ". This item has a long label and will be wrapped.";
      }
      _items.add(ItemData(label, ValueKey(i)));
    }
  }

  int _indexOfKey(Key key) {
    return _items.indexWhere((ItemData d) => d.key == key);
  }

  bool _reorderCallback(Key item, Key newPosition) {
    int draggingIndex = _indexOfKey(item);
    int newPositionIndex = _indexOfKey(newPosition);

    final draggedItem = _items[draggingIndex];
    setState(() {
      debugPrint("Reordering $item -> $newPosition");
      _items.removeAt(draggingIndex);
      _items.insert(newPositionIndex, draggedItem);
    });
    return true;
  }

  void _reorderDone(Key item) {
    final draggedItem = _items[_indexOfKey(item)];
    debugPrint("Reordering finished for ${draggedItem.title}");
  }

  DraggingMode _draggingMode = DraggingMode.iOS;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ReorderableList(
        onReorder: _reorderCallback,
        onReorderDone: _reorderDone,
        child: CustomScrollView(
          slivers: <Widget>[
            SliverAppBar(
              actions: <Widget>[
                PopupMenuButton<DraggingMode>(
                  child: Container(
                    alignment: Alignment.center,
                    padding: const EdgeInsets.symmetric(horizontal: 30.0),
                    child: const Text("Options"),
                  ),
                  initialValue: _draggingMode,
                  onSelected: (DraggingMode mode) {
                    setState(() {
                      _draggingMode = mode;
                    });
                  },
                  itemBuilder: (BuildContext context) =>
                      <PopupMenuItem<DraggingMode>>[
                    const PopupMenuItem<DraggingMode>(
                        value: DraggingMode.iOS,
                        child: Text('iOS-like dragging')),
                    const PopupMenuItem<DraggingMode>(
                        value: DraggingMode.android,
                        child: Text('Android-like dragging')),
                  ],
                ),
              ],
              pinned: true,
              expandedHeight: 150.0,
              flexibleSpace: const FlexibleSpaceBar(
                title: Text('Demo'),
              ),
            ),
            SliverPadding(
                padding: EdgeInsets.only(
                    bottom: MediaQuery.of(context).padding.bottom),
                sliver: SliverList(
                  delegate: SliverChildBuilderDelegate(
                    (BuildContext context, int index) {
                      return Item(
                        data: _items[index],
                        isFirst: index == 0,
                        isLast: index == _items.length - 1,
                        draggingMode: _draggingMode,
                      );
                    },
                    childCount: _items.length,
                  ),
                )),
          ],
        ),
      ),
    );
  }
}

class Item extends StatelessWidget {
  const Item({
    Key? key,
    required this.data,
    required this.isFirst,
    required this.isLast,
    required this.draggingMode,
  }) : super(key: key);

  final ItemData data;
  final bool isFirst;
  final bool isLast;
  final DraggingMode draggingMode;

  Widget _buildChild(BuildContext context, ReorderableItemState state) {
    BoxDecoration decoration;

    if (state == ReorderableItemState.dragProxy ||
        state == ReorderableItemState.dragProxyFinished) {
      decoration = const BoxDecoration(color: Color(0xD0FFFFFF));
    } else {
      bool placeholder = state == ReorderableItemState.placeholder;
      decoration = BoxDecoration(
          border: Border(
              top: isFirst && !placeholder
                  ? Divider.createBorderSide(context)
                  : BorderSide.none,
              bottom: isLast && placeholder
                  ? BorderSide.none
                  : Divider.createBorderSide(context)),
          color: placeholder ? null : Colors.white);
    }

    Widget dragHandle = draggingMode == DraggingMode.iOS
        ? ReorderableListener(
            child: Container(
              padding: const EdgeInsets.only(right: 18.0, left: 18.0),
              color: const Color(0x08000000),
              child: const Center(
                child: Icon(Icons.reorder, color: Color(0xFF888888)),
              ),
            ),
          )
        : Container();

    Widget content = Container(
      decoration: decoration,
      child: SafeArea(
          top: false,
          bottom: false,
          child: Opacity(
            opacity: state == ReorderableItemState.placeholder ? 0.0 : 1.0,
            child: IntrinsicHeight(
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: <Widget>[
                  Expanded(
                      child: Padding(
                    padding: const EdgeInsets.symmetric(
                        vertical: 14.0, horizontal: 14.0),
                    child: Text(data.title,
                        style: Theme.of(context).textTheme.titleMedium),
                  )),
                  dragHandle,
                ],
              ),
            ),
          )),
    );

    if (draggingMode == DraggingMode.android) {
      content = DelayedReorderableListener(
        child: content,
      );
    }

    return content;
  }

  @override
  Widget build(BuildContext context) {
    return ReorderableItem(
        key: data.key,
        childBuilder: _buildChild);
  }
}

主要功能

  • SliverAppBar 兼容:可以在 CustomScrollView 中使用。
  • 支持大列表:可以处理数千个项目的列表。
  • 平滑的重新排序动画:提供流畅的动画效果。
  • 不同的项高度:支持不同高度的列表项。
  • iOS 和 Android 样式:支持类似 iOS 的拖动手柄和类似 Android 的长按拖动。

注意事项

  • API 稳定性没有保证。
  • 如果你使用的是旧版本的 ReorderableListener,现在需要将其放置在 ReorderableItem 层次结构中以检测触摸并触发实际的重新排序。
  • 你可以使用 DelayedReorderableListener 包裹整个行以获得类似 Material 设计的长按重新排序行为。

通过以上示例代码,你应该能够快速上手并在你的 Flutter 应用中实现可重排的列表。希望这对您有所帮助!


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

1 回复

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


当然,下面是一个关于如何使用 flutter_reorderable_list 插件在 Flutter 中实现列表重排序的示例代码。

首先,确保你的 pubspec.yaml 文件中已经添加了 flutter_reorderable_list 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_reorderable_list: ^0.4.0  # 请根据需要检查最新版本号

然后运行 flutter pub get 来安装依赖。

接下来,在你的 Dart 文件中,你可以按照以下步骤实现列表的重排序功能:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Reorderable List Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<String> items = List<String>.generate(20, (i) => "Item ${i + 1}");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Reorderable List Demo'),
      ),
      body: ReorderableListView(
        // 设置列表项构建器
        builder: (BuildContext context, int index) {
          return ListTile(
            key: ValueKey('item_${items[index]}'),
            title: Text('${items[index]}'),
          );
        },
        // 设置列表项数量
        itemCount: items.length,
        // 设置拖动开始时的回调
        onReorder: (int oldIndex, int newIndex) {
          setState(() {
            if (newIndex > oldIndex) {
              newIndex -= 1;
            }
            final String item = items.removeAt(oldIndex);
            items.insert(newIndex, item);
          });
        },
      ),
    );
  }
}

代码解释:

  1. 依赖引入:确保在 pubspec.yaml 中添加 flutter_reorderable_list 依赖。

  2. 主应用入口:在 main.dart 中,定义 MyAppMyHomePage 类。

  3. 数据定义:在 _MyHomePageState 类中定义一个 List<String> 类型的 items 列表,作为我们要重排序的数据源。

  4. UI构建

    • 使用 Scaffold 作为页面布局容器。
    • body 中使用 ReorderableListView 组件。
    • builder 参数用于构建列表项,这里使用 ListTile 来显示每一项的内容。
    • itemCount 参数指定列表项的数量。
    • onReorder 参数用于处理列表项重排序的逻辑。在拖动结束时,会调用此回调,并传入旧索引 oldIndex 和新索引 newIndex。我们通过 setState 方法更新 items 列表的顺序。
  5. 拖动逻辑处理:在 onReorder 回调中,首先检查新索引是否需要调整(因为移除元素后,后续元素的索引会前移),然后移除旧位置的元素并插入到新位置。

这个示例展示了如何使用 flutter_reorderable_list 插件在 Flutter 中实现一个简单的可重排序列表。你可以根据实际需求进一步自定义列表项的外观和行为。

回到顶部