Files
Colinx-Blog/content/posts/Flutter 拖动排序列表与跨平台优化实践.md
2021-03-30 23:47:22 +08:00

118 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Flutter 拖动排序列表与跨平台优化实践
date: 2021-03-30
lastmod: 2021-03-30
description: Flutter 拖动排序列表与跨平台优化实践
categories:
- 教程
tags:
- 技术
- Flutter
---
# Flutter 拖动排序列表与跨平台优化实践
Flutter中实现拖动排序的列表非常简单使用官方的`ReorderableListView`替代原本的`ListView`即可,`ListView.builder`同理。
```dart
return ReorderableListView(
// padding: const EdgeInsets.symmetric(horizontal: 40),
children: <Widget>[
for (int index = 0; index < _items.length; index++)
ListTile(
key: Key('$index'),
tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
title: Text('Item ${_items[index]}'),
),
],
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final int item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
);
}
```
上面是官方给的demo简洁明了。[官方介绍视频](https://www.youtube.com/watch?v=yll3SNXvQCw)下面的评论里人家直呼比原生Android写的过瘾的多。阅读文档后我给我的App的界面也加上了可拖动排序的功能。效果如下图
![截屏2021-03-30 23.04.59](https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/20210330234001.png)
虽然可以实现拖动了,但是右边有一个按钮很碍眼。不过这个是用来控制拖动的,鼠标移上去才能触发拖动。
翻了翻文档发现,这个地方`ReorderableListView`在移动端和桌面端的处理是不一样的上图桌面macos右边会出现一个dragHandler而移动端则是靠长按列表项触发拖动。
要把这个碍眼的图标去掉,有两个方案:
- 找到定义这个图标的地方更换一个合适的图标并在外面包裹一层仅在鼠标hover时将图标显示以进行拖动其他情况下隐藏
- 将拖动的实现定义为和移动端相同,即都通过长按列表项触发拖动
针对方案一,以`ReorderableListView``Icon`为关键词搜索,很遗憾的是并没有这方面的资料,又翻了翻源码,并没有找到可以自定义右边这个拖拽按钮的实现。
在Flutter官方的Github仓库的issue中[https://github.com/flutter/flutter/issues/66080#issuecomment-771123430](https://github.com/flutter/flutter/issues/66080#issuecomment-771123430) 对相关问题做了阐述,并有提案对`ReorderableListView`进行了改进。该issue对应的pr已经被合并到stable channel查阅相关API后了解到可以使用`buildDefaultDragHandles: false`,关闭默认的拖拽触发实现,再使用`ReorderableDelayedDragStartListener`包裹原先的`ListTile`即可实现桌面端和移动端都通过长按列表项触发拖拽排序。
不过相应的ListTile的`onLongPress`就不能再有响应了。刚好今天完成了滑动删除的实现,现在列表也的删除、排序已经高度可用且多平台统一了。
![截屏2021-03-30 23.21.32](https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/20210330233350.png)
附相关代码实现:
```dart
body: ReorderableListView.builder(
buildDefaultDragHandles: false,
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (oldIndex < newIndex) newIndex -= 1;
var temp = l.removeAt(oldIndex);
l.insert(newIndex, temp);
});
},
itemCount: l.length,
itemBuilder: (context, index) {
final item = l[index];
return Dismissible(
key: item.key,
background: listTileBackground(),
onDismissed: (direction) {
setState(() {
lastDeleted = item;
l.removeAt(index);
});
ScaffoldMessenger.of(context).showSnackBar(msgDeleted);
},
child: ReorderableDelayedDragStartListener(
key: item.key,
index: index,
child: ListTile(
title: Text(item.title),
subtitle: Text(item.content),
contentPadding: EdgeInsets.fromLTRB(16, 8, 16, 8),
onTap: () {
//your function here
},
// onLongPress: () {
// lastDeleted = item;
// l.removeAt(index);
// setState(() {});
// ScaffoldMessenger.of(context)
// .showSnackBar(msgDeleted);
// },
)));
})));
```