适配层事件分发逻辑

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;
        });
    }
}

在这里插入图片描述

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

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐