Flutter 侧滑删除:侧滑删除 之 Dismissble

2019-08-06  本文已影响0人  yanftch

侧滑删除 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
上一篇 下一篇

猜你喜欢

热点阅读