Flutter列表重排序插件flutter_reorderable_list的使用
Flutter列表重排序插件 flutter_reorderable_list
的使用
flutter_reorderable_list
是一个类似于 iOS 的可重排列表插件,支持平滑的动画效果,并且可以在 CustomScrollView
中与 SliverAppBar
一起使用。本文将详细介绍如何使用这个插件,并提供完整的示例代码。
预览
开始使用
要开始使用 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 回复