📚鸿蒙开发往期学习笔录✒️:
✒️ 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
✒️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
✒️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
✒️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
✒️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
✒️ 记录一场鸿蒙开发岗位面试经历~
✒️ 持续更新中……
概述
在复杂的应用界面中,多个组件嵌套时同时绑定手势事件,或者同一个组件同时绑定多个手势,都有可能导致手势事件产生冲突,达不到用户的预期效果。
本文从事件响应的机制入手,介绍手势触发的基本流程,以及如何响应手势事件,了解背后的执行原理,并用来解决冲突问题等。主要包括以下内容:
- 事件响应链收集
- 手势响应优先级
- 手势响应控制
- 常见手势冲突问题
事件响应链收集
在HarmonyOS开发中, 触摸事件 (onTouch事件)是用户与设备交互的基础,是所有手势事件组成的基础,有Down,Move,Up,Cancel四种 触摸事件的类型 。手势均由触摸事件组成,例如,点击为Down+Up,滑动为Down+一系列Move+Up。
触摸事件的分发由 触摸测试 (TouchTest)结果决定,其结果会直接决定哪些控件的事件加入事件响应链(事件响应成员组成的链表),并最终按照响应链顺序判定是否消费。因此了解触摸事件的响应链收集过程,有助于开发者处理手势事件冲突问题。
ArkUI事件响应链收集,根据右子树(按组件布局的先后层级)优先的后序遍历流程。下面通过一个示例来介绍响应链收集的流程,示例伪代码如下:
build() {
StackA() {
ComponentB() {
ComponentC()
}
ComponentD() {
ComponentE()
}
}
}
其中A是最外层组件,B和D是A的子组件,C是B的子组件,E是D的子组件。界面效果示例以及组件树结构图如下:
用户触摸的动作如果发生在组件C上,事件响应链收集的流程如下,根据右子树(按组件布局的先后层级)优先的后序遍历流程,因为触摸点不在右边的树上,所以事件会从左边树的C节点开始往上传,触摸事件(onTouch事件)是冒泡事件默认会向上一直传递下去,直到被消费或者丢弃,允许多个组件同时触发。最终收集到的响应链是C->B->A。
用户触摸的动作如果发生在组件E上,事件响应链收集的流程如下,根据右子树优先的后序遍历流程,所以事件会从右边树的D节点开始往上传。虽然触摸点在组件D和组件B的交集上,但组件D的 hitTestBehavior 属性默认为HitTestMode.Default,D组件收集到事件后会阻塞兄弟节点(组件B),所以没有收集组件A的左子树,最终收集到的响应链是E->D->A。
上面介绍的事件响应链是系统默认的行为,如果需要改变响应的成员,比如触摸组件E的时候,希望把事件传递给B,该怎么实现呢?开发者可以通过设置D组件的hitTestMode属性为HitTestMode.None或者HitTestMode.Transparent来实现,比如设置为HitTestMode.Transparent,那么组件D自身进行触摸测试,同时不阻塞兄弟及父组件。最终收集到的响应链是E->D->B->A。
又例如触摸E组件的时候,只希望E响应触摸事件,不让其它组件响应触摸事件。可以通过 stopPropagation 来阻止事件冒泡,阻止触摸事件往上传递;也可以通过设置E组件的hitTestMode属性为HitTestMode.Block来实现,那么最终收集到的响应链成员只有组件E。
手势响应
前面根据事件响应链收集,确定了响应链成员和事件响应的顺序。然而往往在处理一些业务的时候,需要给组件/不同组件添加更多的手势和事件,比如onClick、API手势gesture 等等,那么哪个事件会得到响应呢?这就需要了解手势响应的优先级了,本节将主要介绍手势的优先级和手势的控制。
手势响应优先级
手势按是否为系统内置手势,可以分为以下两类:
- 系统手势:系统控件默认实现的手势(系统内置手势),即调用某些通用事件内置的手势,比如拖拽,onClick;比如bindmenu内置的点击事件,bindcontextmenu内置的长按手势。
- 自定义手势:通过绑定手势API,例如使用gesture声明的事件回调,绑定长按手势事件方法。
除了触摸事件(onTouch事件)外的所有手势与事件,均是通过基础手势或者组合手势实现的。例如,拖拽事件是由长按手势和滑动手势组成的一个顺序手势。
在默认情况下,这些手势为非冒泡事件,当父组件和子组件绑定同类型的手势时,父子组件绑定的手势事件会发生竞争,子组件会优先识别绑定的手势。
因此,除非显式声明允许多个手势同时成功,否则同一时间只会有一个手势响应。
- 当父子组件均绑定同一类手势时,子组件优先于父组件触发。
- 当同一个组件同时绑定多个手势时,先达到手势触发条件的手势优先触发。
- 当同一个组件绑定相同事件类型的系统手势和自定义手势时,系统手势会优先响应。比如自定义手势TapGesture和系统手势onClick都是单击事件,但是会优先响应onClick事件。
图1手势响应优先级(从左至右,优先级由高到低)