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,
),
),
);
}
}
在指针向下时,框架会对您的应用程序执行命中测试,以确定指针与屏幕接触的位置存在哪个小部件。然后将指针向下事件(以及该指针的后续事件)调度到命中测试找到的最内部窗口小部件。从那里,事件在树上冒泡,并被分派到从最里面的小部件到树的根的路径上的所有小部件。没有用于取消或停止指针事件进一步调度的机制。
要直接从窗口小部件图层侦听指针事件,请使用 Listener 窗口小部件。但是,通常,请考虑使用手势(如下所述)。
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设置了此回调,则会导致崩溃 。
要从小部件图层中聆听手势,请使用 GestureDetector。
代码
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
先前触发onHorizontalDragDown的指针未完成。
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 插件决定尝试在此基础上的回调都是非空识别哪些手势。
当对于屏幕上的给定指针存在多于一个手势识别器时,框架通过使每个识别器加入手势场来消除用户想要的手势。手势竞技场使用以下规则确定哪个手势获胜:
在任何时候,识别器都可以宣告失败并离开竞技场。如果竞技场中只剩下一个识别器,那么识别器就是赢家。
在任何时候,识别器都可以声明胜利,这会导致胜利并且所有剩余的识别器都会丢失。
例如,当消除水平和垂直拖动的歧义时,两个识别器在接收指针向下事件时进入竞技场。识别器观察指针移动事件。如果用户水平移动指针超过一定数量的逻辑像素,则水平识别器将声明胜利并且手势将被解释为水平拖动。类似地,如果用户垂直移动超过一定数量的逻辑像素,则垂直识别器将声明胜利。
当仅存在水平(或垂直)拖动识别器时,手势竞技场是有益的。在这种情况下,竞技场中将只有一个识别器,并且水平拖动将立即被识别,这意味着水平移动的第一个像素可以被视为拖动,并且用户将不需要等待进一步的手势消歧。