写点什么

flutter 系列之: 移动端手势的具体使用

作者:程序那些事
  • 2022-12-19
    广东
  • 本文字数:2929 字

    阅读完需:约 10 分钟

简介

之前我们介绍了 GestureDetector 的定义和其提供的一些基本的方法,GestureDetector 的好处就是可以把任何一个 widget 都赋予类似 button 的功能。


今天将会通过几个具体的例子来讲解一下 GestureDetector 的具体使用。

赋予 widget 可以点击的功能

一般情况下,我们的普通 widget,比如文本是不能进行交互的,但是如果将其用 GestureDetector 进行包装之后,就可以将其伪装成为一个 button。


比如我们有这样一个伪装成 button 的 Container:


Container(        padding: const EdgeInsets.all(12.0),        decoration: BoxDecoration(          color: Colors.green,          borderRadius: BorderRadius.circular(8.0),        ),        child: const Text('My Button'),      )
复制代码


这个 Container 的本质是一个 Text,这个 Container 本身是没有交互功能的,那么如何对其添加交互功能呢?


最简单的办法就是将其使用 GestureDetector 包装起来,如下所示:


GestureDetector(      // The custom button      child: Container(        padding: const EdgeInsets.all(12.0),        decoration: BoxDecoration(          color: Colors.green,          borderRadius: BorderRadius.circular(8.0),        ),        child: const Text('My Button'),      ),    )
复制代码


接下来我们还要为其添加对应的手势,这里我们添加一个 onTap 方法,


GestureDetector(      onTap: ()=> showDialog<String>(        context: context,        builder: (BuildContext context) => AlertDialog(          title: const Text('基本手势'),          content: const Text('这是基本的手势,你学会了吗?'),          actions: <Widget>[            TextButton(              onPressed: () => Navigator.pop(context, 'Cancel'),              child: const Text('Cancel'),            ),            TextButton(              onPressed: () => Navigator.pop(context, 'OK'),              child: const Text('OK'),            ),          ],        ),      ),      ...
复制代码


这里 onTap 会调用一个 showDialog 来弹出一个对话框,运行之后结果如下:


会动的组件

在上面的例子中,我们用手去 tap 按钮是没有互动效果的,也就是说按钮是不会变化的。


那么有没有可能模拟手指的按压效果呢?


答案是肯定的,flutter 为我们提供了一个 InkWell 组件,这样手指按压下组件会产生波纹的效果。


那么 InkWell 和 GestureDetector 有什么联系呢?


InkWell 和 GestureDetector 很类似,都提供了对手势的支持。


在 InkWell 中提供了多种 GestureTapCallback 接口,用接收手势的回调,非常的方便。


在使用上,InkWell 和 GestureDetector 也很类似,我们可以完全照搬 GestureDetector 的用法。


还是上面的例子,我们可以将 GestureDetector 替换成为 InkWell,如下所示:


  Widget build(BuildContext context) {    return InkWell(      onTap: () {        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(          content: Text('Tap'),        ));      },      child: const Padding(        padding: EdgeInsets.all(12.0),        child: Text('Flat Button'),      ),    );  }
复制代码


这里,为了更好的观察手势按压之后的效果,这里 onTap 选择展示一个 flutter 自带的 SnackBar。

可删除的组件

在 app 中的手势应用上,有一个比较常见的用法就是在 list 列表中,向左滑动一个 item,会出现删除的按钮,这种滑动删除的效果,如何在 flutter 中实现呢?


flutter 提供了一个 Dismissible 的组件来实现这个效果。


我们先来看下 Dismissible 的定义:


class Dismissible extends StatefulWidget {    const Dismissible({    required Key key,    required this.child,    this.background,    this.secondaryBackground,    this.confirmDismiss,    this.onResize,    this.onUpdate,    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,    this.behavior = HitTestBehavior.opaque,  }) : assert(key != null),       assert(secondaryBackground == null || background != null),       assert(dragStartBehavior != null),       super(key: key);
复制代码


可以看到 Dismissible 是一个 StatefulWidget,它有两个必须的参数分别是 key 和 child。


key 用来标记要删除 item 的 id,child 是可以滑动删除的组件。


为了演示方便,我们使用 ListView 来展示如何使用 Dismissible。


首先我们构建一个 items 的 list,里面包含了每个 item 要展示的内容:


 final items = List<String>.generate(10, (i) => '动物 ${i + 1}');
复制代码


然后使用 ListView 的 builder 方法来构建 items。并且将每个 items 封装到 Dismissible 中去:


body: ListView.builder(          itemCount: items.length,          itemBuilder: (context, index) {            final item = items[index];            return Dismissible(              key: Key(item),              onDismissed: (direction) {                setState(() {                  items.removeAt(index);                });                ScaffoldMessenger.of(context)                    .showSnackBar(SnackBar(content: Text('$item 被删除了')));              },              child: ListTile(                title: Text(item),              ),            );          },        )
复制代码


这里 Dismissible 的 child 是 ListTile 组件,里面的具体内容就是 Text。


现在 Dismissible 实际上就可以工作了,当你滑动 ListTile 的时候,对应的 item 就会被删除。


为了明显起见,我们可以给 Dismissible 添加一个 background 属性,这样滑动删除的时候就有了一个背景颜色:


              background: Container(color: Colors.red),
复制代码


另外,Dismissible 还有一个 confirmDismiss 属性,可以用来判断是否真的要滑动删除,比如我们只允许从右到左滑动删除,那么可以这样做:


Dismissible(  ...confirmDismiss:confirmResult,...)
Future<bool> confirmResult(DismissDirection direction) async { if(direction == DismissDirection.endToStart){ return true; } return false; }
复制代码


这里的 confirmResult 是一个异步函数,它接收一个 DismissDirection 的参数,这个参数表示的是滑动删除的方向,我们可以通过这个方向来判断是否真正的进行删除操作。

总结

以上就是日常手势的基本使用了,我们可以通过 GestureDetector,InkWell 和 Dismissible 来和手势进行结合来实现相应的功能。


本文的例子:https://github.com/ddean2009/learn-flutter.git


更多内容请参考 www.flydean.com

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 刚刚阅读数: 5
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020-06-07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
flutter系列之:移动端手势的具体使用_flutter_程序那些事_InfoQ写作社区