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组件挂载文本列表
- 注册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
})
}
- 将创建和更新函数注册给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