Flutter_点击事件和手势

Flutter_点击事件和手势

Flutter中的手势系统有两个独立的层。第一层具有原始指针事件,其描述屏幕上指针(例如,触摸,鼠标和测针)的位置和移动。第二层具有手势,其描述由一个或多个指针移动组成的语义动作。

指针

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

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

代码

class MyApp extends StatelessWidget {
  // This widget is the root of your application.

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: (down) {
        print("onPointerDownEvent");
      },
      onPointerMove: (move) {
        print("onPointerMove");
      },
      onPointerUp: (up) {
        print("onPointerUp");
      },
      onPointerHover: (hover) {
        print("onPointerHover");
      },
      onPointerExit: (exit) {
        print("onPointerExit");
      },
      onPointerCancel: (cancle){
        print("onPointerCancel");
      },
      onPointerEnter: (enter) {
        print("onPointerEnter");
      },
      child: Center(
        child: Text(
          "test",
          textDirection: TextDirection.ltr,
        ),
      ),
    );
  }
}
在指针向下时,框架会对您的应用程序执行命中测试,以确定指针与屏幕接触的位置存在哪个小部件。然后将指针向下事件(以及该指针的后续事件)调度到命中测试找到的最内部窗口小部件。从那里,事件在树上冒泡,并被分派到从最里面的小部件到树的根的路径上的所有小部件。没有用于取消或停止指针事件进一步调度的机制。

要直接从窗口小部件图层侦听指针事件,请使用 <b>Listener</b> 窗口小部件。但是,通常,请考虑使用手势(如下所述)。

Listener监听属性

behavior → HitTestBehavior
在命中测试期间如何表现。

onPointerCancel → PointerCancelEventListener
当触发onPointerDown的指针的输入不再指向此接收器时调用。

onPointerDown → PointerDownEventListener
当指针与屏幕(用于触摸指针)接触时调用,或者在此窗口小部件的位置按下其按钮(用于鼠标指针)。

onPointerEnter → PointerEnterEventListener
当指针进入此窗口小部件的区域时调用。

onPointerExit → PointerExitEventListener
当指针离开此窗口小部件的区域时调用。

onPointerHover → PointerHoverEventListener
当未触发onPointerDown的指针改变位置时调用。

onPointerMove → PointerMoveEventListener
当触发onPointerDown的指针改变位置时调用。

onPointerUp → PointerUpEventListener
当触发onPointerDown的指针不再与屏幕接触时调用。

手势

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

  • 点击

    • onTapDown 可能导致点击的指针已在特定位置与屏幕联系。
    • onTapUp 将触发敲击的指针已停止在特定位置接触屏幕。
    • onTap 已经发生了敲击。
    • onTapCancel之前触发的指针onTapDown不会导致点击。
  • 双击

    • onDoubleTap 用户快速连续两次在同一位置点击屏幕。
  • 长按

    • onLongPress 指针长时间保持与相同位置的屏幕接触。
  • 垂直拖动

    • onVerticalDragStart 指针已接触屏幕,可能会开始垂直移动。
    • onVerticalDragUpdate 与屏幕接触并垂直移动的指针在垂直方向上移动。
      onVerticalDragEnd 之前与屏幕接触并垂直移动的指针不再与屏幕接触,并且在停止接触屏幕时以特定速度移动。
  • 水平拖动

    • onHorizontalDragStart 指针已接触屏幕,可能开始水平移动。
    • onHorizontalDragUpdate 与屏幕接触并水平移动的指针在水平方向上移动。
    • onHorizontalDragEnd 先前与屏幕接触并且水平移动的指针不再与屏幕接触,并且当它停止接触屏幕时以特定速度移动。
    • onPanStart指针已接触屏幕,可能开始水平或垂直移动。如果 - onHorizontalDragStart或onVerticalDragStart设置了此回调,则会导致崩溃 。
    • onPanUpdate指针与屏幕接触并沿垂直或水平方向移动。如果 - onHorizontalDragUpdate或onVerticalDragUpdate设置了此回调,则会导致崩溃 。
    • onPanEnd之前与屏幕接触的指针不再与屏幕接触,并且在停止接触屏幕时以特定速度移动。如果onHorizontalDragEnd或 - onVerticalDragEnd设置了此回调,则会导致崩溃 。

要从小部件图层中聆听手势,请使用 <b>GestureDetector</b>。

代码

class MyApp extends StatelessWidget {
  // This widget is the root of your application.

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        print("onPointerDownEvent");
      },
      onDoubleTap: () {
        print("onDoubleTap");
      },
      onForcePressEnd: (end) {
        print("onForcePressEnd");
      },
      onForcePressPeak: (peak) {
        print("onForcePressPeak");
      },
      onForcePressStart: (start) {
        print("onForcePressStart");
      },
      onForcePressUpdate: (update) {
        print("onForcePressUpdate");
      },
      onHorizontalDragCancel: () {
        print("onHorizontalDragCancel");
      },
      onHorizontalDragDown: (down) {
        print("onHorizontalDragDown");
      },
      onHorizontalDragEnd: (end) {
        print("onHorizontalDragEnd");
      },
      onHorizontalDragStart: (start) {
        print("onHorizontalDragStart");
      },
      onHorizontalDragUpdate: (update) {
        print("onHorizontalDragUpdate");
      },
      onLongPressDragStart: (start) {
        print("onLongPressDragStart");
      },
      onLongPressDragUp: (up) {
        print("onLongPressDragUp");
      },
      onLongPressDragUpdate: (update) {
        print("onLongPressDragUpdate");
      },
      //监听更多方法可以在这里添加
      child: Center(
        child: Text(
          "test",
          textDirection: TextDirection.ltr,
        ),
      ),
    );
  }
}

GestureDetector监听属性

behavior → HitTestBehavior
在命中测试期间,此手势检测器应如何表现

child → Widget
树中此小部件下方的小部件。

dragStartBehavior → DragStartBehavior
确定处理拖动开始行为的方式。

excludeFromSemantics → bool
是否从语义树中排除这些手势。例如,用于显示工具提示的长按手势被排除,因为工具提示本身直接包含在语义树中,因此具有显示它的手势将导致信息的重复。

onDoubleTap → GestureTapCallback
用户快速连续两次在同一位置点击屏幕。

onForcePressEnd → GestureForcePressEndCallback
指针不再与屏幕接触。

onForcePressPeak → GestureForcePressPeakCallback
指针与屏幕接触并以最大力按下。力量至少是 ForcePressGestureRecognizer.peakPressure。

onForcePressStart → GestureForcePressStartCallback
指针与屏幕接触,并用足够的力按压以启动压力。力量至少是 ForcePressGestureRecognizer.startPressure。

onForcePressUpdate → GestureForcePressUpdateCallback
指针与屏幕接触,之前已经通过了 ForcePressGestureRecognizer.startPressure,并且要么在屏幕的平面上移动,要么用不同的力按压屏幕,要么同时按两个屏幕。

onHorizontalDragCancel → GestureDragCancelCallback
先前触发onHorizo​​ntalDragDown的指针未完成。

onHorizontalDragDown → GestureDragDownCallback
指针已接触屏幕,可能开始水平移动。

onHorizontalDragEnd → GestureDragEndCallback
前与屏幕接触并且水平移动的指针不再与屏幕接触,并且当它停止接触屏幕时以特定速度移动。

onHorizontalDragStart → GestureDragStartCallback
指针已接触屏幕并开始水平移动。

onHorizontalDragUpdate → GestureDragUpdateCallback
与屏幕接触并水平移动的指针在水平方向上移动。

onLongPress → GestureLongPressCallback
指针长时间保持与相同位置的屏幕接触。

onLongPressDragStart → GestureLongPressDragStartCallback
指针长时间保持与相同位置的屏幕接触。

onLongPressDragUp → GestureLongPressDragUpCallback
无论长按后是否拖动指针,触发长按的指针都停止接触屏幕。

onLongPressDragUpdate → GestureLongPressDragUpdateCallback
长按后,指针已被拖动。

onLongPressUp → GestureLongPressUpCallback
触发长按的指针已停止接触屏幕。

onPanCancel → GestureDragCancelCallback
先前触发onPanDown的指针未完成。

onPanDown → GestureDragDownCallback
指针已接触屏幕并可能开始移动。

onPanEnd → GestureDragEndCallback
先前与屏幕接触并移动的指针不再与屏幕接触,并且当它停止接触屏幕时以特定速度移动。

onPanStart → GestureDragStartCallback
指针已经接触屏幕并开始移动。

onPanUpdate → GestureDragUpdateCallback
与屏幕接触并移动的指针再次移动。

onScaleEnd → GestureScaleEndCallback
指针不再与屏幕接触。

onScaleStart → GestureScaleStartCallback
与屏幕接触的指针已建立焦点,初始比例为1.0。

onScaleUpdate → GestureScaleUpdateCallback
与屏幕接触的指针表示新的焦点和/或比例。

onTap → GestureTapCallback
已经发生了敲击

onTapCancel → GestureTapCancelCallback
先前触发onTapDown的指针不会导致点击。

onTapDown → GestureTapDownCallback
可能导致点击的指针已在特定位置与屏幕联系。

onTapUp → GestureTapUpCallback
将触发敲击的指针已停止在特定位置接触屏幕。

onVerticalDragCancel → GestureDragCancelCallback
先前触发onVerticalDragDown的指针未完成。

onVerticalDragDown → GestureDragDownCallback
指针已接触屏幕,可能会开始垂直移动。

onVerticalDragEnd → GestureDragEndCallback
之前与屏幕接触并垂直移动的指针不再与屏幕接触,并且在停止接触屏幕时以特定速度移动。

onVerticalDragStart → GestureDragStartCallback
指针已接触屏幕并已开始垂直移动。

onVerticalDragUpdate → GestureDragUpdateCallback
与屏幕接触并垂直移动的指针在垂直方向上移动。
如果您正在使用Material Components,那么这些小部件中的许多小部件已经响应了轻击或手势。例如, IconButton和 FlatButton 响应按下(轻击),并 ListView 响应滑动以触发滚动。如果您没有使用这些小部件,但想要点击“墨水溅”效果,则可以使用 InkWell。

手势消歧

在屏幕上的给定位置处,可能存在多个手势检测器。所有这些手势检测器在它们经过并且尝试识别特定手势时监听指针事件流。该 GestureDetector 插件决定尝试在此基础上的回调都是非空识别哪些手势。

当对于屏幕上的给定指针存在多于一个手势识别器时,框架通过使每个识别器加入手势场来消除用户想要的手势。手势竞技场使用以下规则确定哪个手势获胜:

在任何时候,识别器都可以宣告失败并离开竞技场。如果竞技场中只剩下一个识别器,那么识别器就是赢家。

在任何时候,识别器都可以声明胜利,这会导致胜利并且所有剩余的识别器都会丢失。

例如,当消除水平和垂直拖动的歧义时,两个识别器在接收指针向下事件时进入竞技场。识别器观察指针移动事件。如果用户水平移动指针超过一定数量的逻辑像素,则水平识别器将声明胜利并且手势将被解释为水平拖动。类似地,如果用户垂直移动超过一定数量的逻辑像素,则垂直识别器将声明胜利。

当仅存在水平(或垂直)拖动识别器时,手势竞技场是有益的。在这种情况下,竞技场中将只有一个识别器,并且水平拖动将立即被识别,这意味着水平移动的第一个像素可以被视为拖动,并且用户将不需要等待进一步的手势消歧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容