Flutter开发者

Flutter中手势事件处理

2018-03-23

上期回顾

在前面的文章中我们我们学习了StatefulWidget有状态组件的用法,并且让大家试一试官方Demo中,点击FloatActionButton使文字字数增加的同时,增大字体的大小。

这个的做法很简单,就是通过TextStyle把计数器的值赋值给Text文本就行了,但是要注意的时,最好给TextSize的大小写一个最小值,如从10.0开始(10.0+_counter)。

由于很简单,就不在给大家贴代码了。

在上篇文章中,我们还给大家介绍了FloatActionButton的onPressed参数,需要传入一个没有参数没有返回值的方法,这其实就是FloatActionButton点击事件的处理。

那么这篇文章我们就来看下Flutter中事件的处理

引言

在Flutter中的手势事件分为两层,第一层有原始指针事件,它描述了屏幕上指针(例如,触摸,鼠标和触控笔)的位置和移动。第二层有手势,描述由一个或多个指针移动组成的语义动作。

虽然指针在我们开发中不常用到,但是我们还是会分别对指针很手势进行介绍

指针Pointers

指针代表关于用户与设备屏幕交互的原始数据。有四种类型的指针事件:

  • PointerDownEvent 指针已经联系了特定位置的屏幕。
  • PointerMoveEvent 指针已经从屏幕上的一个位置移动到另一个位置。
  • PointerUpEvent 指针停止接触屏幕。
  • PointerCancelEvent 来自此指针的输入不再针对此应用。

在指针向下时,框架对您的应用程序执行命中测试,以确定指针与屏幕相接的位置存在哪些小部件。指针向下事件(以及该指针的后续事件)然后被分派到由命中测试发现的最内部的小部件。

从那里开始,这些事件会冒泡到树中(事件分发),并被分派到从最内部的小部件到树根的路径上的所有小部件。没有任何机制可以取消或停止进一步调度指针事件。

由于指针不能直接用于控件的监听,所以我们在开发中一般使用Gesture来监听用户的各种事件。

手势Gestures

手势表示可以从多个单独的指针事件识别的语义动作(例如,轻敲,拖动和缩放),甚至可能是多个单独的指针。手势可以分派多个事件,对应于手势的生命周期(例如,拖动开始,拖动更新和拖动结束):

单击

  • onTapDown 可能导致水龙头的指针已经在特定位置与屏幕接触。
  • onTapUp 将触发水龙头的指针已停止在特定位置与屏幕接触。
  • onTap 出现了水龙头。
  • onTapCancel先前触发的指针onTapDown不会导致敲击。

双击

  • onDoubleTap 用户快速连续两次在同一位置轻敲屏幕。

长按

  • onLongPress 指针在相同位置长时间保持与屏幕接触。

垂直拖动

  • onVerticalDragStart 指针已经与屏幕联系并可能开始垂直移动。
  • onVerticalDragUpdate 与屏幕接触并垂直移动的指针已沿垂直方向移动。
  • onVerticalDragEnd 先前与屏幕接触并垂直移动的指针不再与屏幕接触,并且在停止接触屏幕时以特定速度移动。

水平拖拽

  • onHorizontalDragStart 指针已经与屏幕联系并可能开始水平移动。
  • onHorizontalDragUpdate 与屏幕接触并水平移动的指针已沿水平方向移动。
  • onHorizontalDragEnd 先前与屏幕接触并水平移动的指针不再与屏幕接触,并且在停止接触屏幕时以特定速度移动。

要让Gesture可以监听Widget的各种事件需要使用GestureDetector来处理这些事件。

我们来看下GestureDetector的构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
GestureDetector({
Key key,
this.child,
this.onTapDown,
this.onTapUp,
this.onTap,
this.onTapCancel,
this.onDoubleTap,
this.onLongPress,
this.onVerticalDragDown,
this.onVerticalDragStart,
this.onVerticalDragUpdate,
this.onVerticalDragEnd,
this.onVerticalDragCancel,
this.onHorizontalDragDown,
this.onHorizontalDragStart,
this.onHorizontalDragUpdate,
this.onHorizontalDragEnd,
this.onHorizontalDragCancel,
this.onPanDown,
this.onPanStart,
this.onPanUpdate,
this.onPanEnd,
this.onPanCancel,
this.onScaleStart,
this.onScaleUpdate,
this.onScaleEnd,
this.behavior,
this.excludeFromSemantics: false
})

GestureDetector有很多的参数,但是基本上每个参数都是对应一个事件,大家可以根据自己的需要来选择相应的事件来做监听处理。

好吧,还是来举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

import 'package:flutter/material.dart';

void main() {
runApp(new MaterialApp(home: new MyApp()));
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {

return new Scaffold(
appBar: new AppBar(
title: new Text("Gestures"),
),
body: new Center(
child: new GestureDetector(
child: new Icon(
Icons.android,
size: 200.0,
),
onTap: () {
print("onTap");
},
onDoubleTap: () {
print("onDoubleTap");
},
onLongPress: () {
print("onLongPress");
},
onVerticalDragStart: (details){
print("在垂直方向开始位置:"+details.globalPosition.toString());
}, onVerticalDragEnd: (details){
print("在垂直方向结束位置:"+details.primaryVelocity.toString());
},
)),
);
}
}

我们在屏幕的正中心放了一个icon,icon外面被GestureDetector包围着,记录在屏幕上的点击。双击、长按和滑动事件并把事件信息打印出来。

备注:在Flutter使用 print可以在flutter控制台输出信息

控制台输出:

I/flutter (20568): onTap

I/flutter (20568): onDoubleTap

I/flutter (20568): onLongPress

I/flutter (20568): 在垂直方向开始位置:Offset(154.0, 367.3)

I/flutter (20568): 在垂直方向结束位置:-366.4189656255261

I/flutter (20568): 在垂直方向开始位置:Offset(148.0, 290.3)

I/flutter (20568): 在垂直方向结束位置:619.5150358985436

  • 当我们单击屏幕是,日志便会打印onTap
  • 当我们双击屏幕时,日志便会打印onDoubleTap,同时屏蔽点击事件
  • 当我们长按屏幕时,日志便会打印onLongPress,同时屏蔽单击事件
  • 当我们在屏幕滑动时,会打印屏幕上的滑动事件,同时屏蔽Tap事件

在前面的文章中我们已经说,没有返回值和参数的函数可以直接使用函数名调用,这样我们就可以把触摸事件抽离出去做自己的处理。

事件冲突处理

正常情况下,我们仅仅会在一个方向上操作界面,但是是也不排除用户在横向和竖向操作界面(或者是多个手势),这样一来屏幕就会给底层发来多个手势识别器,这样一样就会存在手势的冲突。

  • 如果两个手势都在操作,最后剩下的识别器会享有事件的处理权
  • 如果横竖两个识别器同时存在,最先划出屏幕的识别器享有事件处理权

上述两个是Flutter中事件冲突时获取滑动事件的规则。

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

打赏请备注姓名或者昵称,方便我后期统计哦

关注公众号,及时查阅最新文章