HarmonyOS Next开发学习手册——使用NDK接口构建UI(嵌入ArkTS组件)

ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Native侧提供,如声明式UI语法,自定义struct组件,UI高级组件。

针对需要使用ArkTS侧独立能力的场景,ArkUI开发框架提供了Native侧嵌入ArkTS组件的能力,该能力依赖 ComponentContent 机制,通过ComponentContent完成对ArkTS组件的封装,然后将封装对象转递到Native侧,通过Native侧的 OH_ArkUI_GetNodeHandleFromNapiValue 接口转化为ArkUI_NodeHandle对象用于Native侧组件挂载使用。

说明

  • 通过OH_ArkUI_GetNodeHandleFromNapiValue接口获得的ArkUI_NodeHandle对象只能作为子组件参数使用,如 addChild 接口的第二个参数,将该对象使用在其他场景下,如 setAttribute 设置属性将不生效并返回错误码。

  • 针对Native侧修改ArkTS组件的场景,需要在Native侧通过Node-API方式构建ArkTS侧的更新数据,再通过ConmponnetContent的 update 接口更新。

  • 自定义场景 下,相关函数如measureNode等无法对ArkTS模块内部的组件进行调用。

以下示例代码在 接入ArkTS页面 章节基础上引入ArkTS的Refresh组件。

图1 Refresh组件挂载文本列表

  1. 注册ArkTS组件创建函数给Native侧,以便Native侧调用,创建函数使用ComponentContent能力进行封装。
// MixedModule.ets
// 使用ComponentContent能力创建ArkTS组件

import { NodeContent } from '@ohos.arkui.node'
import { UIContext } from '@ohos.arkui.UIContext';
import { RefreshModifier } from '@ohos.arkui.modifier';
import { ComponentContent } from '@ohos.arkui.node'

// 定义Native侧和ArkTS进行交互的数据对象。
interface NativeRefreshAttribute {
  isRefreshing: boolean;
  width?: number;
  height?: number;
  backgroundColor?: number;
  refreshOffset?: number;
  pullToRefresh?: boolean
  onRefreshing?: () => void;
  onOffsetChange?: (offset: number) => void;
}

// 定义@Builder函数的入参格式。
interface RefreshAttribute {
  isRefreshing: boolean;
  // 属性设置通过Modifier优化性能
  modifier?: RefreshModifier;
  slot?: NodeContent;
  onRefreshing?: () => void;
  onOffsetChange?: (offset: number) => void;
}

// ComponnetContent封装ArkTS组件依赖全局@Builder函数,涉及复杂自定义组件场景,可以在@Builder函数中嵌套@Component自定义组件。
// @Builder函数提供入参方式,方便后续通过ComponentContent的update接口进行参数更新。
@Builder
function mixedRefresh(attribute: RefreshAttribute) {
  Refresh({ refreshing: attribute.isRefreshing }) {
    // Refresh作为容器组件,需要使用ContentSlot机制预留子组件占位
    ContentSlot(attribute.slot)
  }.attributeModifier(attribute.modifier)
  .onRefreshing(() => {
    console.info("on onRefreshing");
    if (attribute.onRefreshing) {
      console.info("on native onRefreshing");
      attribute.onRefreshing();
    }
  })
  .onOffsetChange((value: number) => {
    console.info("on offset change: " + value);
    if (attribute.onOffsetChange) {
      console.info("on native onOffsetChange");
      attribute.onOffsetChange(value);
    }
  })
}

// 定义创建函数的返回值,用于ArkTS侧和Native侧的交互。
interface MixedModuleResult {
  // 定义针对Refresh构建函数的封装对象,用于Native侧转化为ArkUI_NodeHandle对象。
  content?: ComponentContent<RefreshAttribute>;
  // Refresh作为容器组件,需要使用ContentSlot机制挂载Native侧的子组件。
  childSlot?: NodeContent;
}

// 提供创建ArkTS组件的入口函数。
export function createMixedRefresh(value: NativeRefreshAttribute): MixedModuleResult {
  console.info("createMixedRefresh");
  // 通过AppStorage对象在Ability启动的时候保持UI上下文对象。
  let uiContent = AppStorage.get<UIContext>("context");
  let modifier = new RefreshModifier();
  if (value.width) {
    modifier.width(value.width)
  }
  if (value.height) {
    modifier.height(value.height)
  }
  if (value.backgroundColor) {
    modifier.backgroundColor(value.backgroundColor)
  }
  if (value.pullToRefresh) {
    modifier.pullToRefresh(value.pullToRefresh)
  }
  if (value.refreshOffset) {
    modifier.refreshOffset(value.refreshOffset)
  }
  // 创建NodeContent插槽对象用于Refresh子组件挂载。
  let nodeSlot = new NodeContent();
  // 通过ComponentContent创建Refresh组件并将它封装起来。
  let content = new ComponentContent<RefreshAttribute>(uiContent!, wrapBuilder<[RefreshAttribute]>(mixedRefresh),
    {
      isRefreshing: value.isRefreshing,
      modifier: modifier,
      slot: nodeSlot,
      onRefreshing: value.onRefreshing,
      onOffsetChange: value.onOffsetChange
    });
  // 将Refresh组件的封装对象及其子组件插槽对象传递给Native侧。
  return { content: content, childSlot: nodeSlot };
}

// 定义Refresh组件的更新函数,用于Native侧更新。
// 在更新场景下,需要将Refresh组件的封装对象及其子组件插槽对象返回,防止组件重新创建。
export function updateMixedRefresh(refresh: ComponentContent<RefreshAttribute>, childSlot: NodeContent,
  value: NativeRefreshAttribute): void {
  let modifier = new RefreshModifier();
  if (value.width) {
    modifier.width(value.width)
  }
  if (value.height) {
    modifier.height(value.height)
  }
  if (value.backgroundColor) {
    modifier.backgroundColor(value.backgroundColor)
  }
  if (value.pullToRefresh) {
    modifier.pullToRefresh(value.pullToRefresh)
  }
  if (value.refreshOffset) {
    modifier.refreshOffset(value.refreshOffset)
  }
  // 调用ComponentContent的update接口进行更新。
  refresh.update({
    isRefreshing: value.isRefreshing,
    modifier: modifier,
    slot: childSlot,
    onRefreshing: value.onRefreshing,
    onOffsetChange: value.onOffsetChange
  })
}
  1. 将创建和更新函数注册给Native侧。
// entry.ets
import nativeNode from 'libentry.so';
import { NodeContent } from '@ohos.arkui.node';
import { createMixedRefresh, updateMixedRefresh } from './MixedModule'

@Entry
@Component
struct Index {
  private rootSlot = new NodeContent();
  @State @Watch('changeNativeFlag') showNative: boolean = false;

  aboutToAppear(): void {
    // 设置uiContext;
    AppStorage.setOrCreate<UIContext>("context", this.getUIContext());
    // 设置混合模式下的builder函数。
    nativeNode.registerCreateMixedRefreshNode(createMixedRefresh);
    nativeNode.registerUpdateMixedRefresh
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值