大家好,我是坚果,
今天是Flutter系列第七节。今天给大家介绍flutter手势
Flutter的安装与设置(第一节)
35分钟教你学会dart(第二节)
每个 Flutter 开发人员都应该知道的 16 个 Dart 技巧和窍门(第三节)
flutter架构(第四节)
如何在flutter中构建响应式布局(第五节)
flutter的版本控制工具fvm(第六节)
Flutter 提供了一些非常棒的开箱即用的小部件,它们预先构建用于处理触摸事件,例如 in<code>InkWell</code>和<code>InkResponse</code>。这些小部件包装您的小部件,以便它们能够响应触摸事件。除了这样做之外,它还会将 Material Ink 飞溅添加到您的小部件中。<code>InkResponse</code>例如,当飞溅超出小部件的边界时,它具有控制形状和剪裁的选项。一个有趣的一点要注意的是<code>InkWell</code>,并<code>InkResponse</code>没有做任何渲染,而不是他们更新父材料部件。一个常见的例子是图像。如果将图像包裹在 中<code>inkWell</code>,您会注意到波纹不可见。这是因为它是在Material上的图像后面绘制的。为了使<code>Ink</code>飞溅可见,使用<code>Ink.Image</code>. 虽然对大多数任务很有用,但如果您想捕获更多事件,例如当用户在屏幕上拖动时,应使用<code>GestureDetector</code>.
那么什么是手势检测?它是如何工作的?
手势检测的基本概述是一个无状态小部件,它在其构造函数中具有用于不同触摸事件的参数。值得注意的是,您不能将<code>Pan</code>and<code>Scale</code>一起使用,因为它<code>Scale</code>是<code>Pan</code>. <code>GestureDetector</code>仅用于检测手势,因此不提供任何视觉响应(不存在Material Ink传播)。
<code>GestureDetector</code>根据哪些回调是非空的,决定尝试识别哪些手势。这很有用,因为如果您需要禁用手势,您将传递*null*。
让我们以<code>**onTap**</code>手势为例,确定<code>**GestureDetector**</code>.
首先,我们创建一个带有<code>onTap</code>回调的 GestureDetector ,因为它是非空的,<code>GestureDetector</code>当点击事件发生时将使用我们的回调。在 内部<code>GestureDetector</code>,创建了一个手势工厂。<code>Gesture Recognizer</code>努力确定正在处理的手势。对于所有提供的不同回调,此过程都是相同的<code>GestureDetector</code>。在<code>GestureFactories</code>随后被传递到<code>RawGestureDetector</code>。
<code>RawGestureDetector</code>做检测手势的艰苦工作。它是一个有状态的小部件,它在状态改变时同步所有手势,处理识别器,获取所有发生的指针事件并将其发送到注册的识别器。然后他们在Gesture Arena 中展开决斗。
<code>RawGestureDetector</code>build 方法由 a 组成,<code>Listener</code>它是侦听指针事件的基类。如果您想使用来自平台的原始输入,如上升、下降或取消事件,这是您的首选课程。<code>Listener</code>不给你任何的手势,只是基本的<code>onPointerDown</code>,<code>onPointerUp</code>,<code>onPointerMove</code>和<code>onPointerCancel</code>事件。一切都必须手动处理,包括向Gesture Arena报告自己。如果您不这样做,那么您不会被自动取消,也无法参与那里发生的交互。这是小部件方面的最低级别。
<code>Listener</code>是一个<code>SingleChildRenderObjectWidget</code>由<code>RenderPointerListener</code>extends类组成的类,这<code>RenderProxyBoxWithHitTestBehavior</code>意味着它在允许<code>HitTestBehavior</code>自定义的同时模仿其子项的属性。
<code>HitTestBehaviour</code>有 3 个选项<code>deferToChild</code>,<code>opaque</code>和<code>translucent</code>。这些来自并配置在<code>GestureDetector</code>. <code>DeferToChild</code>默认行为。<code>Opaque</code>阻止在后台的小部件接收事件并<code>Translucent</code>允许后台小部件接收事件。
那么如果您希望父级和子级都接收指针事件呢?
让我们想象一下您有一个嵌套列表并且想要同时滚动这两个列表的情况。为此,您需要父级和子级都接收该指针。您将命中测试行为配置为半透明,确保两个小部件都接收事件,但事情没有按计划进行……这是为什么?
那么,上述问题的答案是<code>GestureArena</code>。
<code>GestureArena</code>用于手势消歧。所有识别器都被发送到这里,他们在那里进行了战斗。在屏幕上的任何给定点,都可以有多个手势识别器。Arena 考虑了用户触摸屏幕的时间长度、倾斜度以及用户拖动的方向来确定获胜者。
父列表和子列表都将它们的识别器发送到竞技场,但(在撰写本文时)只有一个会获胜,而且总是碰巧是子列表。
解决方法是将 a<code>RawGestureDetector</code>与您自己的<code>GestureFactory</code>'s一起使用,这会改变竞技场的表现方式。
例如,让我们创建一个由两个容器组成的简单应用程序。目标是让孩子和父母都收到手势。
两者都将被包裹在一个<code>RawGestureDetector</code>. 接下来,我们将创建一个自定义手势识别器,<code>AllowMultipleGestureRecognizer</code>. <code>GestureRecognizer</code>是所有其他识别器从其继承的基类。它为类提供了基本的 API,以便它们能够与手势识别器一起工作/交互。值得注意的是,<code>GestureRecognizer</code>它并不关心识别器本身的具体细节。
在上面的代码中,我们创建了一个<code>AllowMultipleGestureRecognizer</code>扩展<code>TapGestureRecognizer</code>. 这意味着它能够继承<code>TapGestureRecognizer</code>. 在这个例子中,我们覆盖<code>rejectGesture</code>这样的,而不是处理识别器,它被手动接受。
现在我们将我们的自定义手势识别器传递<code>GestureRecognizerFactoryWithHandlers</code>给<code>RawGestureDetector</code>.
现在我们将我们的自定义手势识别器传递<code>GestureRecognizerFactoryWithHandlers</code>给<code>RawGestureDetector</code>. 该工厂需要两个属性,一个构造函数和一个用于构造和初始化手势识别器的初始化器。我们使用 lambda 来传递这些参数。如上面代码中所述,构造函数返回一个新实例,<code>AllowMultipleGestureRecognizer</code>而初始化器采用<code>instance</code>用于侦听点击并将一些文本打印到控制台的属性。这将对两个容器重复,唯一的区别是打印的文本。
这是示例应用程序的完整源代码:
那么运行上述代码的结果是什么呢?
当您点击黄色容器时,两个小部件都会收到点击,因此控制台会打印两条语句。
该应用程序:

控制台输出
回到我们的Tap示例,在发生这种情况后,<code>onTap</code>现在将执行映射到的函数。
总结
今天我们研究了 Flutter 框架如何处理手势。我们首先查看 Flutter 提供的用于处理点击和其他触摸事件的出色的预构建小部件。接下来,我们继续<code>GestureDetector</code>研究它的内部工作方式。通过一个例子,我们了解了 Flutter 是如何处理 Tap 手势的。我们穿越了这片土地<code>RawGestureDetector</code>,<code>Listener</code>聆听并欣赏了被称为的秘密 Flutter 搏击俱乐部的声音<code>GestureArena</code>。
最后,我们从应用程序的角度介绍了 Flutter 中的大部分手势系统。有了这些知识,您现在应该更好地了解屏幕上的触摸是在幕后进行的。如果您有任何问题或疑虑,请随时和我联系,下面是我的公众号,
那我们下节再见!