几乎每个应用程序都需要某种用户输入。通常你的应用程序需要对触摸事件做出反应。这是一个关于触摸事件的小指南,特别是对于刚开始的Flutter开发者。
当涉及到手势识别和对触摸事件的反应时,Flutter为新的开发者提供了令人难以置信的小部件。你可以让你的应用程序中的任何部件对触摸事件做出反应,只需将其包裹在这些触摸识别部件中的一个。
无论您是刚刚了解Flutter上触摸事件管理的开发者,还是想快速回顾一下的专业人士,这篇文章都能让您快速了解。
手势系统是如何运作的?
基本上,Flutter 中的手势系统在两个不同的层面上运行。第一层存储原始的指针事件,描述物理细节,如使用中的指针的位置和移动,如测针、鼠标和一般的触控。
在这之上,我们有一个 "手势 "层。这将指针的运动解释为有意义的语义,并为指针的运动增加了一个背景。
初学者的快速触摸事件词汇
除非你了解语义手势和指针,否则无法处理触摸事件。指针是这个领域的英雄!你会看到这在字面上是如何实现的,如下。
在我们探讨个别元素的反应之前,让我们先看看案例中涉及的特征。
指针
指针代表了与用户与有关屏幕的互动有关的原始数据。有四种不同类型的指针事件。
PointerUpEvent:指 针已停止与屏幕的交互。PointerDownEvent:指针在一个特定的位置上与屏幕接触。PointerMoveEvent:指针已经移动到屏幕上的一个新位置。PointerCancelEvent:这个指针的输入不再指向正在进行的应用程序。
当你参与PointerDownEvent ,框架将检查应用程序,以确定位于应用程序线框上该特定点的小部件。PointerDownEvent将被派发到该widget和它上面的widget到组件树的根部,任何跟随该特定路径上的向下事件的事件也会被派发。
手势
如前所述,手势代表了语义上的动作,如点击、缩放和拖动,这些动作很容易从一个指针活动中出现的多个单独事件中识别出来。一个手势可能包含多个触摸事件,每个事件都处理手势的一个独特的里程碑,如拖动开始或拖动结束!
以下是Flutter上触摸事件管理中涉及的最常见的手势类型。
点触手势
onTapUp:指针触发了对屏幕上某一特定位置的点击。onTapDown:指针可能导致在屏幕上接触到一个点。onTap:当指针先前触发了onTapDown,也触发了onTapUp,导致轻拍。onTapCancel:当指针触发onTapDown,不会引起轻拍。
双击手势
onDoubleTap:用户在同一位置快速连续敲击屏幕两次。
长按手势
onLongPress:指针在同一位置上与屏幕保持较长时间的接触。
垂直拖动手势
onVerticalDragStart:指针接触屏幕大概垂直移动。onVerticalDragEnd:指 针在垂直移动过程中先前与屏幕接触,以与移动本身相似的速度结束与屏幕的接触。onVerticalDragUpdate:与屏幕接触的指针在同一方向上垂直移动。
水平拖动手势
onHorizontalDragStart:指针与屏幕接触后有可能在水平方向上移动。onHorizontalDragEnd:指针与屏幕接触后,以前以特定的速度在水平方向上移动,现在完全失去了接触。onHorizontalDragUpdate:指针与屏幕接触后水平移动,从onHorizontalDragStart。
平移手势
onPanStart: 指针已经接触到屏幕并可能在X或Y轴上移动。当onHorizontalDragStart或onVerticalDragStart,这个回调会导致崩溃--事件系统没有办法区分平移或拖动的区别。onPanEnd指针与屏幕接触并以特定速度移动的指针失去了与屏幕的接触。当回调设置为onHorizontalDragEnd或onVerticalDragEnd时,会导致崩溃。onPanUpdate:指针目前与屏幕接触并以水平或垂直方向移动。只有在设置onHorizontalDragUpdate或onVerticalDragUpdate的回调时才会发生崩溃。
了解手势歧义
在屏幕上的任何给定位置都可能存在多个手势检测器。所有这些探测器都遵循流过的指针事件的线索。为了试图识别特定的手势,GestureDetector widget根据已经设置的回调来确定指定的语义手势。意思是说,如果你在GestureDetector 上设置了一个特定的回调,该小组件将试图根据该类型的手势来解释指针事件。
该框架在手势领域中对手势进行了区分。每种类型的手势都有一个识别器,在竞技场上竞争,检查进入的指针位置和运动事件。与输入手势相对应的识别器通过遵循一些规则获胜。
- 一个识别器可以在任何时候自由地宣布失败并离开竞技场。当只剩下一个识别器时,它就赢了!
- 一个识别器可以在任何时候宣布胜利,并迫使其他人宣称失败。
例如,假设你想识别垂直和水平拖曳。每个直接的识别器在收到第一个事件事件后就会进入手势竞技场。然后他们将以任何给定方向的逻辑像素来观察移动。
如果移动事件主要是垂直进行的,垂直识别器将由于逻辑像素的交叉而宣布胜利,因此该手势将被解释为在屏幕上的垂直拖动。同样的一系列事件也可以重复用于水平拖动。
如果你只想识别水平拖动,那么运动中是否有垂直成分并不重要,只有水平运动才会被识别。
在Flutter中编码触摸事件处理
setOnClickListener在Android中工作时,您可以通过OnClick ,来响应按钮的点击。但当涉及到Flutter时,您可以选择两种不同的方法来添加一个触摸监听器。
如果widget支持使用监听器,那么你可以传递一个回调函数来处理该事件。这里有一个onPressed 和RaisedButton 参数的代码样本。
class BodyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
print("Click!");
},
child: Align(
alignment: Alignment.center,
child: new Text("Button", softWrap: true)
),
);
}
}
而这是它在你的应用程序中的样子。
.png)
GestureDetector示例
然而,你经常想使用一个小组件还不支持的监听器。当一个监听器不被小组件直接支持时,你可以将该小组件包装在GestureDetector ,并将处理程序传递给onTap 参数。下面是方法。
class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Flutter_App(),
);
}
}
class Flutter_App extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _State();
}
}
class _State extends State<Flutter_App>
with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(primaryColor: Colors.blue),
home: Scaffold(
appBar: AppBar(
title: Text('Flutter App'),
),
body: Center(
child: GestureDetector(
child: FlutterLogo(
size: 200.0,
),
onTap: () {
print("Tap");
},
),
)));
}
@override
void dispose() {
// Resource release
super.dispose();
}
}
而这个应用程序会是这样的。
.png)
双击的动画示例
这里是另一个触摸事件反应的主要例子,双击Flutter标志会引起视觉旋转。
.gif)
.gif)
.gif)
想知道如何监听双击事件吗?这就是方法。
class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: AnimateApp(),
);
}
}
class AnimateApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AnimateAppState();
}
}
class _AnimateAppState extends State<AnimateApp>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
CurvedAnimation curve;
@override
void initState() {
super.initState();
// Create AnimationController object
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 2000));
curve = CurvedAnimation(parent: controller, curve: Curves.easeIn);
// Create Animation object through Tween object
animation = Tween(begin: 50.0, end: 200.0).animate(controller)
..addListener(() {
// Note: This sentence cannot be omitted, otherwise the widget will not be redrawn and the animation effect will not be seen
setState(() {});
});
// Perform animation
controller.forward();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AnimateApp',
theme: ThemeData(primaryColor: Colors.blue),
home: Scaffold(
appBar: AppBar(
title: Text('AnimateApp'),
),
body: Center(
child: GestureDetector(
child: RotationTransition(
turns: curve,
child: FlutterLogo(
size: 200.0,
)),
onDoubleTap: () {
if (controller.isCompleted) {
controller.reverse();
} else {
controller.forward();
}
},
),
)));
}
@override
void dispose() {
// Resource release
controller.dispose();
super.dispose();
}
}
最后的想法
在Flutter上对触摸事件做出反应并不像人们想象的那样复杂。了解小部件的性质和它们的监听能力是你需要的第一课。而其他的事情都会在这里顺利进行。