ACE框架特性调研——手势事件流程分析 原创 精华
作者:王清
前言:
ACE全称是Ability Cross-platform Environment (元能力跨平台执行环境),是应用在OpenHarmony上的UI框架。作为一个UI框架,需要提供视图布局,UI组件,事件响应机制等的支持,并且当前主流的应用终端都为触摸屏,UI的操作大都通过手势完成,我们这里就对ACE框架的手势事件流程做一个简单的分析。
事件手势分类:
从鸿蒙开发者网站提供的API上我们可以看到,在基于TS扩展的开发范式说明里,单独对手势做了一个类别,而在基于JS扩展的开发范式说明里,则是归类到通用事件里,名称也略有不同:
代码结构与简单类图:
代码结构:
gesture文件夹下的类图:
这里仅对gesture文件下的文件做一个类图梳理,可以很清晰的看到Gesture类和Recognizer类的对应关系,其中Gesture类会创建一个对应的Recognizer,并set对应相关的OnActionID,priority和Mask,而Recognizer类则是处理手势相关的事件逻辑等。
手势事件流程:
我们仅观测手势事件在ACE框架中的流程,ACE框架中,AceAbility类是运行起始点,一切都从这里开始:
手势事件时序图:
手势事件在ACE框架中的入口是OnPointerEvent,AceAbility里面获取到Container容器和FlutterAceView后就开始对这个pointer事件做一系列的处理:
手势事件示例代码流程:
我们以Pinch为例,对整个手势事件的流程的关键代码做一个分析。
当应用调用相关接口后,JS的Binding操作创建Gesture,然后Gesture里面会创建对应的Recognizer:
Create函数里面会创建一个Gesture实例,并将其push到gestureComponent中:
Gesutre创建对应的Reconizer,来添加对应的事件回调以及设置priority和gestureMask
GestureMask枚举说明:
名称 | 描述 |
---|---|
Normal | 不屏蔽子组件的手势,按照默认手势识别顺序进行识别。 |
IgnoreInternal | 屏蔽子组件的手势,仅当前容器的手势进行识别。子组件上系统内置的手势不会被屏蔽,如子组件为List组件时,内置的滑动手势仍然会触发。 |
事件流程中,Ace起始触发:
Container里面初始化CallBack,context进行PostTask操作,aceView注册回调:
PipelineContext的OnTouchEvent进行处理,里面EventManager的TouchTest进行触摸测试获取触摸事件目标列表touchTestResults_,具体实现在RenderNode函数TouchTest里,TouchTest类似前端的事件冒泡机制,它先从顶部节点开始对所有RenderNode进行深度遍历,然后从最底层的节点开始向上将每个节点收集到一个为TouchTestResult类型的result变量中,最后根据该result进行事件分发。
bool RenderNode::TouchTest(const Point& globalPoint, const Point& parentLocalPoint, const TouchRestrict& touchRestrict,
TouchTestResult& result)
{
if (disableTouchEvent_ || disabled_) {
return false;
}
Point transformPoint = GetTransformPoint(parentLocalPoint);
//判断触摸是否在组件区域
if (!InTouchRectList(transformPoint, GetTouchRectList())) {
return false;
}
const auto localPoint = transformPoint - GetPaintRect().GetOffset();
bool dispatchSuccess = false;
const auto& sortedChildren = SortChildrenByZIndex(GetChildren());
//进行深度遍历
if (IsChildrenTouchEnable()) {
for (auto iter = sortedChildren.rbegin(); iter != sortedChildren.rend(); ++iter) {
auto& child = *iter;
if (!child->GetVisible() || child->disabled_ || child->disableTouchEvent_) {
continue;
}
if (child->TouchTest(globalPoint, localPoint, touchRestrict, result)) {
dispatchSuccess = true;
break;
}
if (child->IsTouchable() && (child->InterceptTouchEvent() || IsExclusiveEventForChild())) {
auto localTransformPoint = child->GetTransformPoint(localPoint);
for (auto& rect : child->GetTouchRectList()) {
if (rect.IsInRegion(localTransformPoint)) {
dispatchSuccess = true;
break;
}
}
}
}
}
auto beforeSize = result.size();
for (auto& rect : GetTouchRectList()) {
if (touchable_ && rect.IsInRegion(transformPoint)) {
// Calculates the coordinate offset in this node.
globalPoint_ = globalPoint;
const auto coordinateOffset = globalPoint - localPoint;
coordinatePoint_ = Point(coordinateOffset.GetX(), coordinateOffset.GetY());
OnTouchTestHit(coordinateOffset, touchRestrict, result);
break;
}
}
auto endSize = result.size();
return (dispatchSuccess || beforeSize != endSize) && IsNotSiblingAddRecognizerToResult();
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
事件的分发,touchTestResults_是上面代码TouchTest里面获取:
RenderGestureListener继承RenderProxy类,RenderProxy继承自RenderNode类,RenderGestureListener重新实现了OnTouchTestHit函数,以返回用于接收触摸事件的触摸目标对象,coordinateOffset作为recognizer来计算触摸点的局部位置。这里面注册pinchRecognizer,这样在接收到pinch事件时即可触发创建pinchRecognizer时添加的事件回调:
此外,每个Recognizer类都重新实现ReconcileFrom函数将给定recognizer的状态转换为this。 实现必须检查给定的recognizer类型是否与当前的类型匹配。 如果匹配失败,返回值应该为false 如果成功则为true
最后每个Recognizer类里都有相应事件的具体处理逻辑函数HandleXXXEVENT对事件做处理,调用SendCallbackMsg函数将信息传递到GestureEvent里:
GestureEvent给上层JS调用,如:JsGestureFunction::Execute(const GestureEvent& info)
手势事件代码流程总结:
我们再用文字流程的方式对时序图和代码流程做一个总结:
总结:
在ACE框架中,手势和事件都是相对复杂的板块,一篇文章无法涵盖全部信息,本文仅对手势事件的流程做一个简单阐述,难免有些疏漏,欢迎指正补充,有兴趣的读者也可以考虑对其进一步研究。
引用:
通用事件与通用手势说明:
更多原创内容请关注:深开鸿技术团队
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
感谢作者推开了手势事件的大门,赶快了解一下