Flutter 117: 图解 Dismissible 滑动清除 Widget

简介: 0 基础学习 Flutter,第一百一十七步:简单了解滑动清除 Dismissible 小组件!

    和尚在尝试在项目中实现类似于 iOS 邮箱邮件左右滑动删除对应邮件时,参考到 Flutter 提供的 Dismissible,虽与理想的有差别,但还是值得研究一下。

Dismissible

源码分析

const Dismissible({
    @required Key key,
    @required this.child,
    this.background,            // 滑动背景展示 Widget
    this.secondaryBackground,   // 与background相反滑动背景展示 Widget
    this.confirmDismiss,        // 是否确定清除当前 Widget
    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,
})

    分析源码可得,其中 key 是必须参数,key 作为 Widget 的唯一标识,对应滑动删除的组件,在列表中不建议直接用索引作为 key 的唯一标识,因为关闭窗口小部件可能会更改其他窗口小部件的索引;

案例源码

_listWid() => ListView.builder(itemCount: 20, itemBuilder: (context, index) => _disItem(index));

_listItem(index) {
  return Column(children: <Widget>[
    Container( height: 55.0,
        margin: EdgeInsets.symmetric(horizontal: 20),
        child: Row(children: <Widget>[
          Expanded(child: Text('当前 item = ${(index + 1)}', style: TextStyle(fontSize: 16.0))),
          Padding(child: Icon(Icons.lock_open, size: 14.0), padding: EdgeInsets.only(left: 10.0))
        ])),
    Container(height: 0.5, color: Colors.grey)
  ]);
}

_disItem(index) => Dismissible(key: UniqueKey(), child: _listItem(index));

1. background

    background 为堆叠在 Dismissible 设置的 child 元素后的 Widget,在滑动过程中展示的背景 Widget;对于未设置 secondaryBackground 时,各个方向的滑动展示的背景均为 background

_backgroundWid() {
  return Container( color: Colors.red,
      child: Align( alignment: Alignment.centerRight,
          child: Padding( padding: EdgeInsets.symmetric(horizontal: 20.0),
              child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    Icon(Icons.delete_forever, color: Colors.white, size: 18.0),
                    SizedBox(height: 5.0),
                    Text('Delete', style: TextStyle(color: Colors.white))
                  ]))));
}

2. secondaryBackground

    secondaryBackgroundbackground 类似,仅支持在向上滑动或从右向左滑动方向上展示的背景 Widget

_secondBackgroundWid() {
    return Container( color: Colors.green,
      child: Align( alignment: Alignment.centerLeft,
          child: Padding( padding: EdgeInsets.symmetric(horizontal: 20.0),
              child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    Icon(Icons.edit, color: Colors.white, size: 18.0),
                    SizedBox(height: 5.0),
                    Text('Edit', style: TextStyle(color: Colors.white))
                  ]))));
}

3. direction

    direction 为限制滑动关闭方向,在 onDismissed / confirmDismiss 中也可以进行判断;

  • DismissDirection.vertical 竖直方向,包括 up / down 两种
  • DismissDirection.horizontal 水平方向,包括 endToStart / startToEnd 两种
  • DismissDirection.endToStart 结束到开始方向(与语言设置的 rtlltr 相关),汉英等日常方向一般是从右至左
  • DismissDirection.startToEnd 开始到结束方向(与语言设置的 rtlltr 相关),汉英等日常方向一般是从左至右
  • DismissDirection.up 由下向上
  • DismissDirection.down 由上向下
return Padding(padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
    child: Dismissible(
      key: Key('${_direction.toString()}'),
      child: Container(height: 100.0,
          child: Center(child: Text('${_direction.toString()}', style: TextStyle(color: Colors.white, fontSize: 16.0))),
          decoration: BoxDecoration(color: _color, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(20.0))),
      direction: _direction,
      background: Container(decoration: BoxDecoration(color: Colors.grey, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(20.0))),
    ));

4. confirmDismiss & onDismissed & onResize

    confirmDismiss 返回的是 Future 类型的数据,用于判断是否清除当前 Widget,返回 true 时清除此 Widget,否则将其移回到其原始位置;当返回 false / null 时,均不会进入 onDismissed / onResize 回调;其中 onDismissed 为确认清除当前 Widget 的回调,onResize 为当前 Widget 改变尺寸时的回调;在 confirmDismiss / onDismissed 中可以根据 direction 滑动方向进行单独判断;

_itemDialog(context, _direction) {
  bool _value = false;
  return showDialog<bool>(context: context,
      builder: (context) {
        return AlertDialog(
          title: Row(children: <Widget>[
            Icon(Icons.settings), SizedBox(width: 8),
            Text(_direction == DismissDirection.endToStart ? 'Delete' : 'Edit')
          ]),
          content: Icon(_direction == DismissDirection.endToStart ? Icons.delete_forever : Icons.edit, color: _direction == DismissDirection.endToStart ? Colors.red : Colors.green),
          actions: <Widget>[
            FlatButton(child: const Text('No'),
                onPressed: () { Navigator.pop(context, true); _value = false; }),
            FlatButton(child: const Text('Yes'),
                onPressed: () { Navigator.pop(context, true); _value = true; })
          ]); }).then((val) {
    val = _value; return val;
  });
}

5. dismissThresholds

    dismissThresholds 可根据各方向设置不同的阀值,对应的是一个 Map 集合;范围在(0.0, 1.0) 之间,设置的阀值越大,代表滑动范围越大才可以触发 onDismissed 回调;

dismissThresholds: {
  DismissDirection.startToEnd: 0.8,
  DismissDirection.endToStart: 0.3
},

6. crossAxisEndOffset

    crossAxisEndOffset 用于定义当前清除 Widget 在滑动过程中,沿主轴方向最后的偏移量,根据定义的值来确定最后位置;

crossAxisEndOffset: -5.0,


    Dismissible 案例源码


    和尚对于 Dismissible 的研究还不够深入,如有错误,请多多指导!

来源: 阿策小和尚
目录
相关文章
|
7月前
|
前端开发 机器人 数据安全/隐私保护
Flutter笔记:手写并发布一个人机滑动验证码插件
写 Flutter 项目时,遇到需要滑块验证码功能。滑块验证码属于人机验证码的一种,看起来像是在一个图片中“挖去”了一块,然后通过用户手动操作滑块,让被“挖去”的部分移回来。由于我不想使用各种第三方模块,因此决定自己实现一个初版以后慢慢添砖加瓦。本文是对第一个版本的一点记录。
186 1
Flutter笔记:手写并发布一个人机滑动验证码插件
|
14天前
|
开发框架 前端开发 搜索推荐
【Flutter前端技术开发专栏】Flutter中的自定义Widget与渲染流程
【4月更文挑战第30天】探索Flutter的自定义Widget与渲染流程。自定义Widget是实现复杂UI设计的关键,优点在于个性化设计、功能扩展和代码复用,但也面临性能优化和复杂性管理的挑战。创建步骤包括设计结构、定义Widget类、实现构建逻辑和处理交互。Flutter渲染流程涉及渲染对象树、布局、绘制和合成阶段。实践案例展示如何创建带渐变背景和阴影的自定义按钮。了解这些知识能提升应用体验并应对开发挑战。查阅官方文档以深入学习。
【Flutter前端技术开发专栏】Flutter中的自定义Widget与渲染流程
|
14天前
|
JavaScript 前端开发 开发者
【Flutter前端技术开发专栏】Flutter中的Widget与状态管理
【4月更文挑战第30天】本文探讨了Flutter的Widget和状态管理。Widget是Flutter构建UI的基础,分为有状态和无状态两种。状态管理确保UI随应用状态变化更新,影响应用性能和可维护性。文章介绍了`setState`、`Provider`、`Riverpod`、`Bloc`和`Redux`等状态管理方法,并通过计数器应用展示了其实现。选择合适的状态管理策略对高效开发至关重要。
【Flutter前端技术开发专栏】Flutter中的Widget与状态管理
|
18天前
|
前端开发 开发者 UED
Flutter的自定义Painter:深入探索自定义绘制Widget的技术实现
【4月更文挑战第26天】Flutter的自定义Painter允许开发者根据需求绘制独特UI,通过继承`CustomPaint`类和重写`paint`方法实现。在`paint`中使用`Canvas`绘制图形、路径等。创建自定义Painter类后,将其作为`CustomPaint` Widget的`painter`属性使用。此技术可实现自定义形状、渐变、动画等复杂效果,提升应用视觉体验。随着Flutter的进化,自定义Painter将提供更丰富的功能。
|
18天前
|
编解码 算法 开发者
Flutter的布局系统:深入探索布局Widget与布局原则
【4月更文挑战第26天】Flutter布局系统详解,涵盖布局Widget(Row/Column、Stack、GridView/ListView、CustomSingleChildLayout)和布局原则(弹性布局、约束优先、流式布局、简洁明了)。文章旨在帮助开发者理解并运用Flutter的布局系统,创建适应性强、用户体验佳的界面。通过选择合适的布局Widget和遵循原则,可实现复杂且高效的UI设计。
|
18天前
|
开发框架 搜索推荐 Android开发
Flutter的Widget基础:概念、分类与深入探索
【4月更文挑战第26天】Flutter Widget详解:基础、分类与工作原理。Widget是Flutter UI的核心,描述界面外观而非直接渲染。分为基础、布局、可滚动及状态管理四大类。基于响应式编程,状态变化时自动更新UI。了解其概念、分类和原理,能助开发者高效构建精美应用。随着Flutter生态发展,Widget系统潜力无限。
|
8月前
|
Dart 前端开发 开发工具
谷歌移动UI框架Flutter教程之Widget
谷歌移动UI框架Flutter教程之Widget
|
9月前
Flutter源码分析笔记:Widget类源码分析
本文记录阅读与分析Flutter源码 - Widget类源码分析。
62 0
Flutter源码分析笔记:Widget类源码分析
|
10月前
|
API Android开发 容器
Flutter控件之基类Widget封装
基类的Widget主要确定以下几个方面,第一就是,自定义一个抽象类还是非抽象类,第二、继承方式,采取有状态还是无状态,第三、关于组件的点击方式,如何进行实现。
112 0
Flutter万物皆为Widget
Flutter 中的 Widget 是描述界面元素的基本单元,可以包含视觉和交互元素。Widget 可以嵌套、组合和扩展,从而构建出复杂的 UI 界面。在 Flutter 中,Widget 可以分为两种类型:StatelessWidget 和 StatefulWidget。
Flutter万物皆为Widget