Flutter事件监听

一. 事件监听

在大前端的开发中,必然存在各类各样和用户交互的状况:好比手指点击、手指滑动、双击、长按等等。html

全部内容首发于公众号:coderwhy前端

在Flutter中,手势有两个不一样的层次:vue

  • 第一层:原始指针事件(Pointer Events):描述了屏幕上由触摸板、鼠标、指示笔等触发的指针的位置和移动。
  • 第二层:手势识别(Gesture Detector):这个是在原始事件上的一种封装。
    • 好比咱们要监听用户长按,若是本身封装原始事件咱们须要监遵从用户按下到抬起的时间来判断是不是一次长按事件;
    • 好比咱们须要监听用户双击事件,咱们须要本身封装监听用户两次按下抬起的时间间隔;
    • 幸运的是各个平台几乎都对它们进行了封装,而Flutter中的手势识别就是对原始指针事件的封装;
    • 包括哪些手势呢?好比点击、双击、长按、拖动等

2.1. 指针事件Pointer

Pointer 表明的是人机界面交互的原始数据。一共有四种指针事件:web

Pointer的原理是什么呢?算法

  • 在指针落下时,框架作了一个 hit test 的操做,肯定与屏幕发生接触的位置上有哪些Widget以及分发给最内部的组件去响应;api

  • 事件会沿着最内部的组件向组件树的根冒泡分发;数据结构

  • 而且不存在用于取消或者中止指针事件进一步分发的机制;app

原始指针事件使用Listener来监听:框架

class HomeContent extends StatelessWidget {
 @override  Widget build(BuildContext context) {  return Center(  child: Listener(  child: Container(  width: 200,  height: 200,  color: Colors.red,  ),  onPointerDown: (event) => print("手指按下:$event"),  onPointerMove: (event) => print("手指移动:$event"),  onPointerUp: (event) => print("手指抬起:$event"),  ),  );  } } 复制代码
image-20190925154947943
image-20190925154947943

2.2. 手势识别Gesture

Gesture是对一系列Pointer的封装,官方建议开发中尽量使用Gesture,而不是Pointerless

建议使用Gesture
建议使用Gesture

Gesture分层很是多的种类:

点击

  • onTapDown:用户发生手指按下的操做
  • onTapUp:用户发生手指抬起的操做
  • onTap:用户点击事件完成
  • onTapCancel:事件按下过程当中被取消

双击:

  • onDoubleTap:快速点击了两次

长按:

  • onLongPress:在屏幕上保持了一段时间

纵向拖拽:

  • onVerticalDragStart:指针和屏幕产生接触并可能开始纵向移动;
  • onVerticalDragUpdate:指针和屏幕产生接触,在纵向上发生移动并保持移动;
  • onVerticalDragEnd:指针和屏幕产生接触结束;

横线拖拽:

  • onHorizontalDragStart:指针和屏幕产生接触并可能开始横向移动;
  • onHorizontalDragUpdate:指针和屏幕产生接触,在横向上发生移动并保持移动;
  • onHorizontalDragEnd:指针和屏幕产生接触结束;

移动:

  • onPanStart:指针和屏幕产生接触并可能开始横向移动或者纵向移动。若是设置了 onHorizontalDragStart 或者 onVerticalDragStart,该回调方法会引起崩溃;
  • onPanUpdate:指针和屏幕产生接触,在横向或者纵向上发生移动并保持移动。若是设置了 onHorizontalDragUpdate 或者 onVerticalDragUpdate,该回调方法会引起崩溃。
  • onPanEnd:指针先前和屏幕产生了接触,而且以特定速度移动,此后再也不在屏幕接触上发生移动。若是设置了 onHorizontalDragEnd 或者 onVerticalDragEnd,该回调方法会引起崩溃。

从Widget的层面来监听手势,咱们须要使用:GestureDetector

  • 固然,咱们也可使用RaisedButton、FlatButton、InkWell等来监听手势
  • globalPosition用于获取相对于屏幕的位置信息
  • localPosition用于获取相对于当前Widget的位置信息
class HYHomePage extends StatelessWidget {
 @override  Widget build(BuildContext context) {  return Scaffold(  appBar: AppBar(  title: Text("手势测试"),  ),  body: GestureDetector(  child: Container(  width: 200,  height: 200,  color: Colors.red,  ),  onTap: () {   },  onTapDown: (detail) {  print(detail.globalPosition);  print(detail.localPosition);  },  onTapUp: (detail) {  print(detail.globalPosition);  print(detail.localPosition);  }  ),  );  } }  复制代码
image-20200317172326395
image-20200317172326395

二. 跨组件事件

在组件之间若是有事件须要传递,一方面能够一层层来传递,另外一方面咱们也可使用一个EventBus工具来完成。

其实EventBus在Vue、React中都是一种很是常见的跨组件通讯的方式:

  • EventBus至关因而一种订阅者模式,经过一个全局的对象来管理;
  • 这个EventBus咱们能够本身实现,也可使用第三方的EventBus;

这里咱们直接选择第三方的EventBus:

dependencies:
 event_bus: ^1.1.1 复制代码

第一:咱们须要定义一个但愿在组件之间传递的对象:

  • 咱们能够称之为一个时间对象,也能够是咱们平时开发中用的模型对象(model)
class UserInfo {
 String nickname;  int level;   UserInfo(this.nickname, this.level); } 复制代码

第二:建立一个全局的EventBus对象

final eventBus = EventBus();
复制代码

第三:在某个Widget中,发出事件:

class HYButton extends StatelessWidget {
 @override  Widget build(BuildContext context) {  return RaisedButton(  child: Text("HYButton"),  onPressed: () {  final info = UserInfo("why", 18);  eventBus.fire(info);  },  );  } } 复制代码

第四:在某个Widget中,监听事件

class HYText extends StatefulWidget {
 @override  _HYTextState createState() => _HYTextState(); }  class _HYTextState extends State<HYText> {  String message = "Hello Coderwhy";   @override  void initState() {  super.initState();   eventBus.on<UserInfo>().listen((data) {  setState(() {  message = "${data.nickname}-${data.level}";  });  });  }   @override  Widget build(BuildContext context) {  return Text(message, style: TextStyle(fontSize: 30),);  } } 复制代码

备注:全部内容首发于公众号,以后除了Flutter也会更新其余技术文章,TypeScript、React、Node、uniapp、mpvue、数据结构与算法等等,也会更新一些本身的学习心得等,欢迎你们关注

公众号
公众号
相关文章
相关标签/搜索