Flutter 深刻探讨:手势(第七节)

2021年11月24日 阅读数:5
这篇文章主要向大家介绍Flutter 深刻探讨:手势(第七节),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

你们好,我是坚果,架构


今天是Flutter系列第七节。今天给你们介绍flutter手势app

​​  Flutter的安装与设置(第一节)​​框架

​ ​ 35分钟教你学会dart(第二节)​​less

​ ​每一个 Flutter 开发人员都应该知道的 16 个 Dart 技巧和窍门(第三节)ide

​​​ ​flutter架构(第四节)函数

如何在flutter中构建响应式布局(第五节)工具

flutter的版本控制工具fvm(第六节)布局


Flutter 提供了一些很是棒的开箱即用的小部件,它们预先构建用于处理触摸事件,例如 in​​InkWell​​​和​​InkResponse​​​。这些小部件包装您的小部件,以便它们可以响应触摸事件。除了这样作以外,它还会将 Material Ink 飞溅添加到您的小部件中。​​InkResponse​​​例如,当飞溅超出小部件的边界时,它具备控制形状和剪裁的选项。一个有趣的一点要注意的是​​InkWell​​​,并​​InkResponse​​没有作任何渲染,而不是他们更新父材料部件。一个常见的例子是图像。若是将图像包裹在 中​​inkWell​​,您会注意到波纹不可见。这是由于它是在Material上的图像后面绘制的。为了使​​Ink​​​飞溅可见,使用​​Ink.Image​​​. 虽然对大多数任务颇有用,但若是您想捕获更多事件,例如当用户在屏幕上拖动时,应使用​​GestureDetector​​.测试

那么什么是手势检测?它是如何工做的?

手势检测的基本概述是一个无状态小部件,它在其构造函数中具备用于不一样触摸事件的参数。值得注意的是,您不能将​​Pan​​​and​​Scale​​​一块儿使用,由于它​​Scale​​​是​​Pan​​​. ​​GestureDetector​​仅用于检测手势,所以不提供任何视觉响应(不存在Material Ink传播)。ui


​GestureDetector​​根据哪些回调是非空的,决定尝试识别哪些手势。这颇有用,由于若是您须要禁用手势,您将传递*null*


让咱们以​**onTap**​手势为例,肯定​**GestureDetector**​.

首先,咱们建立一个带有​​onTap​​​回调的 GestureDetector ,由于它是非空的,​​GestureDetector​​​当点击事件发生时将使用咱们的回调。在 内部​​GestureDetector​​,建立了一个手势工厂。​​Gesture Recognizer​​​努力肯定正在处理的手势。对于全部提供的不一样回调,此过程都是相同的​​GestureDetector​​​。在​​GestureFactories​​​随后被传递到​​RawGestureDetector​​。


​RawGestureDetector​​作检测手势的艰苦工做。它是一个有状态的小部件,它在状态改变时同步全部手势,处理识别器,获取全部发生的指针事件并将其发送到注册的识别器。而后他们在Gesture Arena 中展开决斗


​RawGestureDetector​​​build 方法由 a 组成,​​Listener​​​它是侦听指针事件的基类。若是您想使用来自平台的原始输入,如上升、降低或取消事件,这是您的首选课程。​​Listener​​​不给你任何的手势,只是基本的​​onPointerDown​​​,​​onPointerUp​​​,​​onPointerMove​​​和​​onPointerCancel​​事件。一切都必须手动处理,包括向Gesture Arena报告本身。若是您不这样作,那么您不会被自动取消,也没法参与那里发生的交互。这是小部件方面的最低级别

​Listener​​​是一个​​SingleChildRenderObjectWidget​​​由​​RenderPointerListener​​​extends类组成的类,这​​RenderProxyBoxWithHitTestBehavior​​​意味着它在容许​​HitTestBehavior​​自定义的同时模仿其子项的属性。


​HitTestBehaviour​​​有 3 个选项​​deferToChild​​​,​​opaque​​​和​​translucent​​​。这些来自并配置在​​GestureDetector​​​. ​​DeferToChild​默认行为。​​Opaque​​​阻止在后台的小部件接收事件并​​Translucent​​容许后台小部件接收事件。

那么若是您但愿父级和子级都接收指针事件呢?

让咱们想象一下您有一个嵌套列表而且想要同时滚动这两个列表的状况。为此,您须要父级和子级都接收该指针。您将命中测试行为配置为半透明,确保两个小部件都接收事件,但事情没有按计划进行……这是为何?

那么,上述问题的答案是​​GestureArena​​。


​GestureArena​​​用于​手势消歧​。全部识别器都被发送到这里,他们在那里进行了战斗。在屏幕上的任何给定点,均可以有多个手势识别器。Arena 考虑了用户触摸屏幕的时间长度、倾斜度以及用户拖动的方向来肯定获胜者。

父列表和子列表都将它们的识别器发送到竞技场,但(在撰写本文时)只有一个会获胜,并且老是碰巧是子列表。

解决方法是将 a​​RawGestureDetector​​​与您本身的​​GestureFactory​​'s一块儿使用,这会改变竞技场的表现方式。

例如,让咱们建立一个由两个容器组成的简单应用程序。目标是让孩子和父母都收到手势。

二者都将被包裹在一个​​RawGestureDetector​​​. 接下来,咱们将建立一个自定义手势识别器,​​AllowMultipleGestureRecognizer​​​. ​​GestureRecognizer​​​是全部其余识别器从其继承的基类。它为类提供了基本的 API,以便它们可以与手势识别器一块儿工做/交互。值得注意的是,​​GestureRecognizer​​它并不关心识别器自己的具体细节。



// Custom Gesture Recognizer.
// rejectGesture() is overridden. When a gesture is rejected, this is the function that is called. By default, it disposes of the
// Recognizer and runs clean up. However we modified it so that instead the Recognizer is disposed of, it is actually manually added.
// The result is instead you have one Recognizer winning the Arena, you have two. It is a win-win.
class AllowMultipleGestureRecognizer extends TapGestureRecognizer {
@override
void rejectGesture(int pointer) {
acceptGesture(pointer);
}
}

在上面的代码中,咱们建立了一个​​AllowMultipleGestureRecognizer​​​扩展​​TapGestureRecognizer​​​. 这意味着它可以继承​​TapGestureRecognizer​​​. 在这个例子中,咱们覆盖​​rejectGesture​​这样的,而不是处理识别器,它被手动接受。

如今咱们将咱们的自定义手势识别器传递​​GestureRecognizerFactoryWithHandlers​​​给​​RawGestureDetector​​.



Widget build(BuildContext context) {
return RawGestureDetector(
gestures: {
AllowMultipleGestureRecognizer: GestureRecognizerFactoryWithHandlers<
AllowMultipleGestureRecognizer>(
() => AllowMultipleGestureRecognizer(), //constructor
(AllowMultipleGestureRecognizer instance) { //initializer
instance.onTap = () => print('Episode 4 is best! (parent container) ');
},
)
},

如今咱们将咱们的自定义手势识别器传递​​GestureRecognizerFactoryWithHandlers​​​给​​RawGestureDetector​​​. 该工厂须要两个属性,一个构造函数和一个用于构造和初始化手势识别器的初始化器。咱们使用 lambda 来传递这些参数。如上面代码中所述,构造函数返回一个新实例,​​AllowMultipleGestureRecognizer​​​而初始化器采用​​instance​​用于侦听点击并将一些文本打印到控制台的属性。这将对两个容器重复,惟一的区别是打印的文本。

这是示例应用程序的完整源代码:



import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

//Main function. The entry point for your Flutter app.
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: DemoApp(),
),
),
);
}

// Simple demo app which consists of two containers. The goal is to allow multiple gestures into the arena.
// Everything is handled manually with the use of `RawGestureDetector` and a custom `GestureRecognizer`(It extends `TapGestureRecognizer`).
// The custom GestureRecognizer, `AllowMultipleGestureRecognizer` is added to the gesture list and creates a `GestureRecognizerFactoryWithHandlers` of type `AllowMultipleGestureRecognizer`.
// It creates a gesture recognizer factory with the given callbacks, in this case, an `onTap`.
// It listens for an instance of `onTap` then prints text to the console when it is called. Note that the `RawGestureDetector` code is the same for both
// containers. The only difference being the text that is printed(Used as a way to identify the widget)

class DemoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: {
AllowMultipleGestureRecognizer: GestureRecognizerFactoryWithHandlers<
AllowMultipleGestureRecognizer>(
() => AllowMultipleGestureRecognizer(),
(AllowMultipleGestureRecognizer instance) {
instance.onTap = () => print('Episode 4 is best! (parent container) ');
},
)
},
behavior: HitTestBehavior.opaque,
//Parent Container
child: Container(
color: Colors.blueAccent,
child: Center(
//Wraps the second container in RawGestureDetector
child: RawGestureDetector(
gestures: {
AllowMultipleGestureRecognizer:
GestureRecognizerFactoryWithHandlers<
AllowMultipleGestureRecognizer>(
() => AllowMultipleGestureRecognizer(), //constructor
(AllowMultipleGestureRecognizer instance) { //initializer
instance.onTap = () => print('Episode 8 is best! (nested container)');
},
)
},
//Creates the nested container within the first.
child: Container(
color: Colors.yellowAccent,
width: 300.0,
height: 400.0,
),
),
),
),
);
}
}

// Custom Gesture Recognizer.
// rejectGesture() is overridden. When a gesture is rejected, this is the function that is called. By default, it disposes of the
// Recognizer and runs clean up. However we modified it so that instead the Recognizer is disposed of, it is actually manually added.
// The result is instead you have one Recognizer winning the Arena, you have two. It is a win-win.
class AllowMultipleGestureRecognizer extends TapGestureRecognizer {
@override
void rejectGesture(int pointer) {
acceptGesture(pointer);
}
}

那么运行上述代码的结果是什么呢?

当您点击黄色容器时,两个小部件都会收到点击,所以控制台会打印两条语句。

该应用程序:


Flutter 深刻探讨:手势(第七节)_flutter

控制台输出


Flutter 深刻探讨:手势(第七节)_flutter_02

回到咱们的Tap示例,在发生这种状况后,​​onTap​​如今将执行映射到的函数。

总结

今天咱们研究了 Flutter 框架如何处理手势。咱们首先查看 Flutter 提供的用于处理点击和其余触摸事件的出色的预构建小部件。接下来,咱们继续​​GestureDetector​​​研究它的内部工做方式。经过一个例子,咱们了解了 Flutter 是如何处理 Tap 手势的。咱们穿越了这片土地​​RawGestureDetector​​​,​​Listener​​​聆听并欣赏了被称为的秘密 Flutter 搏击俱乐部的声音​​GestureArena​​。

最后,咱们从应用程序的角度介绍了 Flutter 中的大部分手势系统。有了这些知识,您如今应该更好地了解屏幕上的触摸是在幕后进行的。若是您有任何问题或疑虑,请随时和我联系,下面是个人公众号,Flutter 深刻探讨:手势(第七节)_flutter_03

那咱们下节再见!