【鸿蒙实战开发】Fabric 自定义组件开发指南

1.编写 RN 调用 Fabric 组件的代码

编写MarqueeViewNativeComponent.tsx,注意,如果要使用 Codegen ,文件必须以NativeComponent命名。在文件中使用 codegenNativeComponent 创建 MarqueeView 组件,其中 MarqueeViewProps 里声明了 src 属性和 onStop 事件:

type OnStopEventData = Readonly<{

isStop: boolean

}>;

interface MarqueeViewProps extends ViewProps {

src: string,

onStop?: DirectEventHandler;

}

const MarqueeView = codegenNativeComponent(

'MarqueeView'

) as HostComponent;

和其他标准组件的创建方式一样,在组件容器内添加 MarqueeView 标签:

 {

SampleTurboModule.rnLog("native调用了RN的 onStop,isStop = "+e.nativeEvent.isStop)

setMarqueeStop(e.nativeEvent.isStop)

}}

/>

2.编写ArkTS原生实现代码

Descriptor 的功能是封装 RN 侧组件代码传递到 ArkUI 组件的参数,MarqueeView 对 RN 侧公开了一个 src 参数,用于显示跑马灯的滚动内容。原生侧定义 MarqueeViewDescriptor 代码如下:

export interface MarqueeViewProps extends ViewBaseProps {

src: string

}

export type MarqueeViewDescriptor = Descriptor<"MarqueeView", MarqueeViewProps>;

Descriptor 不需要我们手动创建,由 rnoh 自动生成;组件 tag 也不需要我们手动设置,rnoh 会为组件自动分配 tag。开发者只需要通过 getDescriptor 方法获取对应 tag 的 Descriptor:

this.descriptor = this.ctx.descriptorRegistry.getDescriptor(this.tag)

当 RN 侧传递过来的属性参数发生变化时,我们需要更新 Descripotor:

this.unregisterDescriptorChangesListener = this.ctx.descriptorRegistry.subscribeToDescriptorChanges(this.tag, (newDescriptor) => {

this.descriptor = (newDescriptor as MarqueeViewDescriptor)

})

RN 调用原生方法

RN 侧调用 UIManager.dispatchViewManagerCommand 向原生发送消息:

UIManager.dispatchViewManagerCommand(

findNodeHandle(nativeRef.current),

'toggleMarqueeState',

[],

)

原生组件通过 commandDispatcher.registerCommandCallback 接收消息并执行对应方法:

this.ctx.commandDispatcher.registerCommandCallback(this.tag, (commandName) => {

if (commandName === "toggleMarqueeState") {

this.start = !this.start

console.log("will emitComponentEvent");

}

})

原生组件调用 RN 侧方法

RN 侧添加 onStop 方法实现:

 {

// 原生组件调用了 RN 侧的 MarqueeView 的 onStop 方法

const isStop = e.nativeEvent.isStop

...

}}

/>

原生侧发送调用 RN 组件事件的消息:

this.ctx.rnInstance.emitComponentEvent(

this.descriptor.tag,

"MarqueeView",

{ type: "onStop", isStop: !this.start }

)

buildCustomComponent

创建 RNSurface 加载 JSBundle 时,传入 buildCustomComponent 用于加载原生 Fabric 组件:

import { RNAbility, ComponentBuilderContext, RNSurface } from "rnoh";

import { MarqueeView } from '../customView/MarqueeView'

@Builder

public buildCustomComponent(ctx: ComponentBuilderContext) {

if (ctx.descriptor.type === MarqueeView.NAME) {

MarqueeView({

ctx: ctx.rnohContext,

tag: ctx.descriptor.tag

})

}

}

...

RNSurface({

...

buildCustomComponent: this.buildCustomComponent,

})

3. 编写 Codegen 的 C++ 代码

开发者可以使用Codegen生成C++侧的胶水代码,也可以手动实现这部分代码。在本节中会详细介绍如何手动实现这部分代码。

  1. 首先创建属性 Props 和 事件 Emitter 两部分的 C++ 类,在 Descriptor 中进行绑定。

  2. 实现 MarqueeViewEventEmitRequestHandler 的 handleEvent 方法,根据原生消息的事件名,调用 eventEmitter 向 RN 侧组件发送事件消息。

  3. 实现 MarqueeViewJSIBinder 类的属性和事件绑定方法。

  4. 实现 MarqueeViewNapiBinder 类的属性映射方法。

  5. 将以上文件引入到 SampleTurboModulePackage 的对应方法实现中进行绑定。

Props

创建 Props 的 C++ 文件用于定义 MarqueeView 的 Descriptor 对应的属性。Props.h:

#include 

#include 

#include 

#include 

namespace facebook {

namespace react {

class JSI_EXPORT MarqueeViewProps final : public ViewProps {

public:

MarqueeViewProps() = default;

MarqueeViewProps(const PropsParserContext &context, const MarqueeViewProps &sourceProps, const RawProps &rawProps);

#pragma mark - Props

std::string src{""};

};

} // namespace react

} // namespace facebook

// Props.cpp

#include 

#include 

#include 

#include "Props.h"

namespace facebook {

namespace react {

MarqueeViewProps::MarqueeViewProps(

const PropsParserContext &context,

const MarqueeViewProps &sourceProps,

const RawProps &rawProps): ViewProps(context, sourceProps, rawProps),

src(convertRawProp(context, rawProps, "src", sourceProps.src, {""}))

{}

} // namespace react

} // namespace facebook

MarqueeViewEventEmitter

MarqueeViewEventEmitter.h 中添加 onStop 方法,并自定义了属性结构体:

#include 

#include 

namespace facebook {

namespace react {

class JSI_EXPORT MarqueeViewEventEmitter : public ViewEventEmitter {

public:

using ViewEventEmitter::ViewEventEmitter;

struct OnStop {

bool isStop;

};

void onStop(OnStop value) const;

};

} // namespace react

} // namespace facebook

MarqueeViewEventEmitter.cpp 中实现 onStop 事件的发送和参数绑定:

#include "MarqueeViewEventEmitter.h"

namespace facebook {

namespace react {

void MarqueeViewEventEmitter::onStop(OnStop event) const {

dispatchEvent("stop", [event = std::move(event)](jsi::Runtime &runtime) {

auto payload = jsi::Object(runtime);

payload.setProperty(runtime, "isStop", event.isStop);

return payload;

});

}

} // namespace react

} // namespace facebook
<

你可能感兴趣的:(鸿蒙开发,HarmonyOS,移动开发,harmonyos,fabric,ui,arkts,组件化开发,移动开发,应用开发)