Flutter 侧滑删除:侧滑删除 之 Dismissble
侧滑删除 Dismissble
侧滑删除,是很多 APP 里边,尤其是列表中常用,比如常见的微信列表,侧滑删除聊天记录,
如果有一天你要用 Flutter 实现列表侧滑操作,你该怎么实现呢?好在是 Flutter 早就考虑到了这个问题,所以早早的就给我们备了一份大餐 Dismissible,直接用他就能实现侧滑删除的功能。
今天总结一下 FLutter 中实现侧滑功能的 widget~Flutter 中实现侧滑删除的功能。
注:源码来源于 Flutter 1.7.8
A widget that can be dismissed by dragging in the indicated [direction].
这是源码中对他的简单介绍,一句话介绍了这个控件的作用.我们先慢慢构建起来。然后通过注释的形式进行总结。
第一步:构建列表
第一步简单,不多说,就是创建一个普通的列表数据,我就用最简单的 ListView 来实现了。代码如下:
@overridevoid initState() {
super.initState();/// 通过 List.generate 方法,生成数据源 datas.addAll(List<String>.generate(20, (int index) => "Item $index"));
}build 方法中不会变动,就是直接构建一个列表UI@overrideWidget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Dismissible 侧滑"),
),body: _buildContent(),
);}构建 ListView 的代码,Item 布局采用了系统自带的 ListTileWidget _buildContent() => ListView.separated(
itemCount: datas.length,
separatorBuilder: (context, index) {
return Divider();
},itemBuilder: (context, index) => _buildItem(index),
);Widget _buildItem(int index) => ListTile(
leading: Icon(Icons.account_circle),
title: Text(datas[index]),
);
第一步结束,实现了一个简单的列表,就不上图了,自己脑补一下吧😆
第二步:添加 Dismissible 组件:
先来看一下他的构造函数:
const Dismissible({
@required Key key,
@required this.child,
this.background,
this.secondaryBackground,
this.confirmDismiss,
this.onResize,
this.onDismissed,
this.direction = DismissDirection.horizontal,
this.resizeDuration = const Duration(milliseconds: 300),
this.dismissThresholds = const <DismissDirection, double>{},
this.movementDuration = const Duration(milliseconds: 200),
this.crossAxisEndOffset = 0.0,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(key != null),
assert(secondaryBackground != null ? background != null : true),
assert(dragStartBehavior != null),
super(key: key);
key :
你会发现,其他 widget 里边的可选项 key,到了这竟然变成了 required ? 为什么呢?先看下官方解释:
/// The [key] argument must not be null because [Dismissible]s are commonly
/// used in lists and removed from the list when dismissed. Without keys, the/// default behavior is to sync widgets based on their index in the list,/// which means the item after the dismissed item would be synced with the/// state of the dismissed item. Using keys causes the widgets to sync/// according to their keys and avoids this pitfall.
[key]参数不能为null,因为[Dismissible]通常在列表中使用,并在解除时从列表中删除。 没有密钥,默认行为是基于列表中的索引来同步窗口小部件,这意味着被解除的项目之后的项目将与被解除的项目的状态同步。 使用键可以使小部件根据其密钥进行同步,从而避免这种陷阱。
啰嗦了那么一堆,说白了其实就是一个意思:key 是 widget 的唯一标示。因为有了key,所以 widget tree 才知道我们删除了什么widget。我的理解就是全局刷新&局部刷新。(如有错误,请帮忙勘正,谢谢~)
direction:
子控件滑动方向。默认水平方向。建议使用 endToStart 便于适配left-to-rightonDismissed: 消失回调事件,比如下边代码就是在这里边刷新了列表数据
confirmDismiss:
/// Gives the app an opportunity to confirm or veto a pending dismissal.////// If the returned Future<bool> completes true, then this widget will be/// dismissed, otherwise it will be moved back to its original location.////// If the returned Future<bool> completes to false or null the [onResize]
/// and [onDismissed] callbacks will not run.
侧滑删除之前要想二次弹框提示,用它。Function 返回值是 Future<bool> ,如果是 true,那么就是确定删除了;如果是 FALSE 的,那么就是取消,同时 onResize & onDismissed 不会调用。
dismissThresholds:
滑动多少会调用 onDismiss 方法,默认是 0.4Widget
key: new Key(datas[index].toString()),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
setState(() {datas.removeAt(index);});},child: ListTile(
leading: Icon(Icons.account_circle),
title: Text(datas[index]),
),);
上述代码实现了,列表 Item 向左侧滑删除,并刷新列表,上 GIF 效果:onDismissed 方法中参数是 direction, 对应了 那几个值~所以如果你在构造函数中不设置的话,你会发现你既能左滑删除,又能右滑删除了。。。这时候你就可以用这个参数判断下了,比如设置成左滑删除,右滑收藏(或许产品会有这样操蛋的需求吧。。。)[图片上传失败...(image-f64a3e-1565081617607)]
swip_to_delete.gif
现在再试试 confirmDismiss 方法,因为返回值是一个 Future 的,所以要如下处理:
confirmDismiss:
confirmDismiss: (_) async {
return _onConfirmDismiss(index);
},
/// 侧滑二次确认
Future<bool> _onConfirmDismiss(int index) async {
return showDialog(
context: context,
builder: (BuildContext ctx) => AlertDialog(
title: Text("Attention"),
content: Text("Confirm to delete ${datas[index]} ?"),
actions: <Widget>[
FlatButton(
child: Text("Confirm"),
onPressed: () {
setState(() {
datas.removeAt(index);
});
Navigator.of(context).pop(true);
},
),
FlatButton(
child: Text("Cancel"),
onPressed: () {
Navigator.of(context).pop(false);
},
)
],
));
}
上图:
swip_delete_confirm.gif