React Native跨平台鸿蒙开发高级应用原理:适配层事件分发逻辑(二)
本文介绍了ArkUI框架中事件分发机制。对于Touch事件,通过TouchEventHandler处理,根据事件类型(DOWN/MOVE/UP/CANCEL)分发给对应的ComponentInstance,最终通过事件发射器传递给JS侧。非Touch事件(如Click)由ArkUINode处理,通过代理模式传递到ViewComponentInstance,再通过事件发射器触发JS回调。文章详细阐述
适配层事件分发逻辑
4.Touch事件的传递给JS侧
上文中写明 TouchEventHandler 对 Touch 事件进行处理,以 ArkUISurface 举例,ArkUISurface 有一个继承了 TouchEventHandler 的成员变量,这个成员变量通过 dispatchTouchEvent 处理这次 Touch 事件。
void onTouchEvent(ArkUI_UIInputEvent* event)override
{
m_touchEventDispatcher.dispatchTouchEvent(event,m_rootView);
}
对于 Touch 事件首先通过 Touch 的位置等因素,获取对应 touchTarget (每个componentInstance 就是一个 touchTarget,下图的名字是 eventTarget)。
class ComponentInstance:public TouchTarget,public std::enable_shared_from_this<ComponentInstance>
for(auto const& targetTouches:touchByTargetId)
{
auto it = m_touchTargetByTouchId.find(targetTouches.second.begin()->identifier);
if(it == m_touchTargetByTouchId.end())
{
continue;
}
auto eventTarget = it->second.lock();
if(eventTarget == nullptr)
{
m_touchTargetByTouchId.erase(it);
continue;
}
}
然后通过 componentInstance 保存的 m_eventEmitter 发送对应的事件给 js 侧,从而触发页面的刷新等操作。
Touch事件有以下四种类型:
- UI_TOUCH_EVENT_ACTION_DOWN
- UI_TOUCH_EVENT_ACTION_MOVE
- UI_TOUCH_EVENT_ACTION_UP
- UI_TOUCH_EVENT_ACTION_CANCEL
switch(action)
{
case UI_TOUCH_EVENT_ACTION_DOWN:
eventTarget->getTouchEventEmitter()->onTouchStart(touchEvent);
break;
case UI_TOUCH_EVENT_ACTION_MOVE:
eventTarget->getTouchEventEmitter()->onTouchMove(touchEvent);
break;
case UI_TOUCH_EVENT_ACTION_UP:
eventTarget->getTouchEventEmitter()->onTouchEnd(touchEvent);
break;
case UI_TOUCH_EVENT_ACTION_CANCEL:
default:
eventTarget->getTouchEventEmitter()->onTouchCancel(touchEvent);
break;
}
5、非Touch事件的传递给js侧
上文中写明,非 Touch 事件由 ArkUINode 处理,对于每个继承了 ArkUINode 的类,重载了 onNodeEvent 方法,以 StackNode 举例,说明RN适配层是如何区分 Click 事件和 Touch 事件。前文说明,StackNode 注册了 Click 事件,所以通过回调,会走到 StackNode 的 onNodeEvent 部分,这里会先判断这个事件类型,这里是 NODE_ON_CLICK 类型,符合要求,但是对于第二个条件 eventArgs[3].i32 (即上文描述的arkUI传递过来的参数),如果是触屏手机,其值为2不满足 eventArgs[3].i32 != 2 的条件。
void StackNode::onNodeEvent(ArkUI_NodeEventType eventType,EventArgs& eventArgs)
{
if(eventType == ArkUI_NodeEventType::NODE_ON_CLICK && eventArgs[3].i32 != 2)
{
onClick();
}
if(eventType == ArkUI_NodeEventType::NODE_ON_HOVER)
{
if(m_stackNodeDelegate != nullptr)
{
if(eventArgs[0].i32)
{
m_stackNodeDelegate->onHoverIn();
}else
{
m_stackNodeDelegate->onHoverOut();
}
}
}
}
所以此时实际上不会触发 Click 的事件,因此 Touch 事件和 Click 事件不会冲突。如果触发了 Click 事件,StackNode 会通过代理 StackNodeDelegate 发送事件。
void StackNode::onClick()
{
if(m_stackNodeDelegate != nullptr)
{
m_stackNodeDelegate->onClick();
}
}
其中 ViewComponentInstance 继承了 StackNodeDelegate,所以实际上走的是 ViewComponentInstance 的 onClick 函数。
namespace rnoh
{
class ViewComponentInstance
:public CppComponentInstance<facebook::react::ViewShardowNode>,public StackNodeDelegate
{
}
}
这个函数通过 ViewComponentInstance 的 m_eventEmitter 发送事件给 JS,从而触发页面的刷新。
void ViewComponentInstance::onClick()
{
if(m_eventEmitter != nullptr)
{
m_eventEmitter->dispatchEvent("click",[=](facebook:jsi::Runtime& runtime)
{auto payload = facebook::jsi::Object(runtime);
return payload;
});
}
}

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
更多推荐

所有评论(0)