HarmonyOS 实战开发 —— Fabric 自定义组件开发


📚往期笔录记录🔖:

🔖鸿蒙(HarmonyOS)北向开发知识点记录~
🔖鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
🔖鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
🔖嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
🔖对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
🔖鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
🔖记录一场鸿蒙开发岗位面试经历~
🔖持续更新中……


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<OnStopEventData>;
}
 
const MarqueeView = codegenNativeComponent<MarqueeViewProps>(
  'MarqueeView'
) as HostComponent<MarqueeViewProps>;

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

<MarqueeView
  src="双十一大促,消费是社会再生产过程中的一个重要环节,也是最终环节。它是指利用社会产品来满足人们各种需要的过程。"
  style={
  
  {height: 180, width: '100%', backgroundColor: 'hsl(210, 80%, 50%)'}}
  onStop={(e) => {
    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<MarqueeViewDescriptor>(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 方法实现:

<MarqueeView
  ...
  onStop={(e) => {
    // 原生组件调用了 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 <jsi/jsi.h>
#include <react/renderer/components/view/ViewProps.h>
#include <react/renderer/core/PropsParserContext.h>
#include <react/debug/react_native_assert.h>
 
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 <react/renderer/components/rncore/Props.h>
#include <react/renderer/core/PropsParserContext.h>
#include <react/renderer/core/propsConversions.h>
#include "Props.h"
 
namespace facebook {
namespace react {
MarqueeViewProps::MarqueeViewProps(
    const PropsParserContext &context, 
    const MarqueeViewProps &so
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值