简介

移动的和PC端有什么不同呢?同样的H5可以运行在APP端,也可以运行在PC端。两者最大的区别就是移动端可以用手势。手势可以做到一些比如左滑右滑,上滑下滑,缩放等操作。

原生的andorid和IOS当然可以做到这些事情,作为一个移动的的开发框架flutter,自然也能够支持手势。flutter中的手势支持叫做GestureDetector,一起来看看flutter中的手势基础吧。

Pointers和Listener

我们先来考虑一下最简单的手势是什么呢?很明显,最简单的手势就是模拟鼠标的点击操作。我们可以将其称之为Pointer event,也就是各种点击事件。

flutter中有四种Pointer事件,这些事件如下所示:

  • PointerDownEvent --表示用手点击了屏幕,接触到了一个widget。
  • PointerMoveEvent --表示手指从一个位置移动到另外一个位置。
  • PointerUpEvent --手指从点击屏幕变成了离开屏幕。
  • PointerCancelEvent --表示手指离开了该应用程序。

那么点击事件的传递机制是什么样的呢?

以手指点击屏幕的PointerDownEvent事件为例,当手指点击屏幕的时候,flutter首先会去定位该点击位置存在的widget,然后将该点击事件传递给该位置的最小widget.

然后点击事件从最新的widget向上开始冒泡,并将其分派到从最里面的widget到树根的路径上的所有widget中。

注意,flutter中并没有取消或停止进一步分派Pointer事件的机制。

要想监听这写Pointer事件,最简单直接的办法就是使用Listener:

class Listener extends SingleChildRenderObjectWidget {
/// Creates a widget that forwards point events to callbacks.
///
/// The [behavior] argument defaults to [HitTestBehavior.deferToChild].
const Listener({
Key? key,
this.onPointerDown,
this.onPointerMove,
this.onPointerUp,
this.onPointerHover,
this.onPointerCancel,
this.onPointerSignal,
this.behavior = HitTestBehavior.deferToChild,
Widget? child,
}) : assert(behavior != null),
super(key: key, child: child);

可以看到Listener也是一种widget,并且可以监听多种Pointer的事件。

我们可以把要监听Pointer的widget封装在Listener中,这样就可以监听各种Pointer事件了,具体的例子如下:

Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints.tight(const Size(300.0, 200.0)),
child: Listener(
onPointerDown: _incrementDown,
onPointerMove: _updateLocation,
onPointerUp: _incrementUp,
child: Container(
color: Colors.lightBlueAccent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pressed or released in this area this many times:'),
Text(
'$_downCounter presses\n$_upCounter releases',
style: Theme.of(context).textTheme.headline4,
),
Text(
'The cursor is here: (${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})',
),
],
),
),
),
); void _incrementDown(PointerEvent details) {
_updateLocation(details);
setState(() {
_downCounter++;
});
} void _incrementUp(PointerEvent details) {
_updateLocation(details);
setState(() {
_upCounter++;
});
} void _updateLocation(PointerEvent details) {
setState(() {
x = details.position.dx;
y = details.position.dy;
});
}

但是对于Lisenter来说只能监听最原始的Pointer事件,所以如果想监听更多类型的手势事件的话,则可以使用GestureDetector.

GestureDetector

GestureDetector可以检测下面这些手势,包括:

  1. Tap

Tap表示的是用户点击的事件,Tap有下面几种事件:

onTapDown
onTapUp
onTap
onTapCancel
  1. Double tap

Double tap表示的是双击事件,Double tap只有一种类型:

onDoubleTap
  1. Long press

Long press表示的是长按。也只有下面一种类型:

onLongPress
  1. Vertical drag

Vertical drag表示的是垂直方向的拉,它有三个事件,分别是:

onVerticalDragStart
onVerticalDragUpdate
onVerticalDragEnd
  1. Horizontal drag

有垂直方向的拉,就有水平方向的拉,Horizontal drag表示的是水平方向的拉,它同样有三个事件,分别是:

onHorizontalDragStart
onHorizontalDragUpdate
onHorizontalDragEnd
  1. Pan

Pan这个东西可以看做是Vertical drag和Horizontal drag的合集, 因为有时候我们是希望同时可以水平或者垂直移动,在这种情况下面,我们就需要使用到Pan的事件:

onPanStart
onPanUpdate
onPanEnd

注意, Pan是和单独的Vertical drag、Horizontal drag是相互冲突的,不能同时使用。

要想监听上面的这些事件,我们可以使用GestureDetector,先看下GestureDetector的定义:

class GestureDetector extends StatelessWidget {
GestureDetector({
Key? key,
this.child,
this.onTapDown,
this.onTapUp,
this.onTap,
this.onTapCancel,
this.onSecondaryTap,
this.onSecondaryTapDown,
this.onSecondaryTapUp,
this.onSecondaryTapCancel,
this.onTertiaryTapDown,
this.onTertiaryTapUp,
this.onTertiaryTapCancel,
this.onDoubleTapDown,
this.onDoubleTap,
this.onDoubleTapCancel,
this.onLongPressDown,
this.onLongPressCancel,
this.onLongPress,
this.onLongPressStart,
this.onLongPressMoveUpdate,
this.onLongPressUp,
this.onLongPressEnd,
this.onSecondaryLongPressDown,
this.onSecondaryLongPressCancel,
this.onSecondaryLongPress,
this.onSecondaryLongPressStart,
this.onSecondaryLongPressMoveUpdate,
this.onSecondaryLongPressUp,
this.onSecondaryLongPressEnd,
this.onTertiaryLongPressDown,
this.onTertiaryLongPressCancel,
this.onTertiaryLongPress,
this.onTertiaryLongPressStart,
this.onTertiaryLongPressMoveUpdate,
this.onTertiaryLongPressUp,
this.onTertiaryLongPressEnd,
this.onVerticalDragDown,
this.onVerticalDragStart,
this.onVerticalDragUpdate,
this.onVerticalDragEnd,
this.onVerticalDragCancel,
this.onHorizontalDragDown,
this.onHorizontalDragStart,
this.onHorizontalDragUpdate,
this.onHorizontalDragEnd,
this.onHorizontalDragCancel,
this.onForcePressStart,
this.onForcePressPeak,
this.onForcePressUpdate,
this.onForcePressEnd,
this.onPanDown,
this.onPanStart,
this.onPanUpdate,
this.onPanEnd,
this.onPanCancel,
this.onScaleStart,
this.onScaleUpdate,
this.onScaleEnd,
this.behavior,
this.excludeFromSemantics = false,
this.dragStartBehavior = DragStartBehavior.start,
})

可以看到GestureDetector是一个无状态的Widget,它和Listner一样,可以接受一个child Widget,然后监听了很多手势的事件。

所以, 一般来说,我们这样来使用它:

GestureDetector(
onTap: () {
setState(() {
// Toggle light when tapped.
_lightIsOn = !_lightIsOn;
});
},
child: Container(
color: Colors.yellow.shade600,
padding: const EdgeInsets.all(8),
// Change button text when light changes state.
child: Text(_lightIsOn ? 'TURN LIGHT OFF' : 'TURN LIGHT ON'),
),
),

注意, 如果GestureDetector中有child,那么onTap的作用范围就在子child的范围。如果GestureDetector中并没有child,那么其作用范围就是GestureDetector的父widget的范围。

手势冲突

因为手势的监听有很多种方式,但是这些方式并不是完全独立的,有时候这些手势可能是互相冲突的。比如前面我们提到的Pan和Vertical drag、Horizontal drag。

如果遇到这样的情况,那么futter会自行进行冲突解决,去选择到底用户执行的是哪个操作。

比如,当用户同时进行水平和垂直拖动的时候,两个识别器在接收到指针向下事件时都会开始观察指针移动事件。

如果指针水平移动超过一定数量的逻辑像素,则水平识别器获胜,然后将该手势解释为水平拖动。 类似地,如果用户垂直移动超过一定数量的逻辑像素,则垂直识别器获胜。

总结

手势识别是移动端的优势项目,大家可以尝试在需要的地方使用GestureDetector,可以达到意想不到的用户效果哦。

更多内容请参考 http://www.flydean.com/05-flutter-gestures/

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

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

flutter系列之:移动端的手势基础GestureDetector的更多相关文章

  1. flutter系列之:深入理解布局的基础constraints

    目录 简介 Tight和loose constraints 理解constraints的原则 总结 简介 我们在flutter中使用layout的时候需要经常对组件进行一些大小的限制,这种限制就叫做c ...

  2. Flutter系列博文链接

    Flutter系列博文链接 ↓: Flutter基础篇: Flutter基础篇(1)-- 跨平台开发框架和工具集锦 Flutter基础篇(2)-- 老司机用一篇博客带你快速熟悉Dart语法 Flutt ...

  3. 【译】使用 Flutter 实现跨平台移动端开发

    作者: Mike Bluestein   | 原文地址:[https://www.smashingmagazine.com/2018/06/google-flutter-mobile-developm ...

  4. 【Flutter】372- Flutter移动端实战手册

    ☝点击上方蓝字,关注我们! 本文字数:3705字 预计阅读时间:28分钟 导 读 Flutter又双叒叕来了!本周推送是我们Flutter系列文章的最终篇!<Flutter移动端实战手册> ...

  5. spring cloud系列教程第四篇-Eureka基础知识

    通过前三篇文章学习,我们搭建好了两个微服务工程.即:order80和payment8001这两个服务.有了这两个基础的框架之后,我们将要开始往里面添加东西了.还记得分布式架构的几个维度吗?我们要通过一 ...

  6. C#开发BIMFACE系列43 服务端API之图纸拆分

    BIMFACE二次开发系列目录     [已更新最新开发文章,点击查看详细] 在上一篇博客<C#开发BIMFACE系列42 服务端API之图纸对比>的最后留了一个问题,在常规业务场景下,一 ...

  7. C#开发BIMFACE系列44 服务端API之计算图纸对比差异项来源自哪个图框

    BIMFACE二次开发系列目录     [已更新最新开发文章,点击查看详细] 在前两篇博客<C#开发BIMFACE系列42 服务端API之图纸对比>.<C#开发BIMFACE系列43 ...

  8. Android 触摸手势基础 官方文档概览

    Android 触摸手势基础 官方文档概览 触摸手势检测基础 手势检测一般包含两个阶段: 1.获取touch事件数据 2.解析这些数据,看它们是否满足你的应用所支持的某种手势. 相关API: Moti ...

  9. Android 触摸手势基础 官方文档概览2

    Android 触摸手势基础 官方文档概览 触摸手势检测基础 手势检测一般包含两个阶段: 1.获取touch事件数据 2.解析这些数据,看它们是否满足你的应用所支持的某种手势. 相关API: Moti ...

随机推荐

  1. vivo大规模 Kubernetes 集群自动化运维实践

    作者:vivo 互联网服务器团队-Zhang Rong 一.背景 随着vivo业务迁移到K8s的增长,我们需要将K8s部署到多个数据中心.如何高效.可靠的在数据中心管理多个大规模的K8s集群是我们面临 ...

  2. NLog自定义Target之MQTT

    NLog是.Net中最流行的日志记录开源项目(之一),它灵活.免费.开源 官方支持文件.网络(Tcp.Udp).数据库.控制台等输出 社区支持Elastic.Seq等日志平台输出 实时日志需求 在工业 ...

  3. ServletContext 对象

    概念:代表整个Web应用 可以和程序的容器通信 (服务器) 获取 通过request对象获取  request.getServletContext(); 通过HTTPServlet获取  this.g ...

  4. Java 将HTML转为Word

    本文以Java代码为例介绍如何实现将HTML文件转为Word文档(.docx..doc).在实际开发场景中可参考此方法来转换.下面详细方法及步骤. 在编辑代码前,请先在程序中导入Spire.Doc.j ...

  5. python小题目练习(八)

    题目:电视剧的收视率排行榜 需求:实现如下图所示需求  代码展示: """Author:mllContent:电视剧的收视率排行榜Date:2020-11-16" ...

  6. Turtle绘图——python简单上手小案例

    Turtle绘图 Turtle模块提供了在二维平面上移动的环境. Turtle可以实现位置.航向和各种可能的状态和动作. import turtle as tu roo = tu.Turtle() # ...

  7. MySQL通过binlog日志恢复数据

    一.查看下自己的MySQL是否开启了binlog日志 # 是否启用binlog日志 OFF:关闭 ON:开启 show variables like 'log_bin'; 二.开启binlog日志 在 ...

  8. svn :不能打开文件“/data/svn/repo/format”: 权限不够

    解决方法:关闭selinux vi /etc/sysconfig/selinux 将其中的SELINUX=enforcing 改为SELINUX=disabled  即可.

  9. 《ASP.NET Core 6框架揭秘》样章发布[200页/5章]

    作为<ASP.NET Core 3 框架揭秘>的升级版,<ASP.NET Core 6框架揭秘>不仅针对ASP.NET Core 6的新特性进行了修订,并添加了若干原来没有的内 ...

  10. JavaScript知识梳理

    JS内功修炼 专业术语 类,封装,继承, 专业术语 babel 块级作用域 函数 扩展对象的功能性 解构 set和map js的类 改进的数组功能 Promise与异步编程 代理和反射 用模块封装代码 ...