鸿蒙NEXT系列之精析NDK UI API(节点增删和属性设置) - 实践
2025-11-11 18:04 tlnshuju 阅读(0) 评论(0) 收藏 举报精析NDK UI API(节点增删和属性设置)
〇、前言
在上一篇,重点是案例的完整实现,使代码达到能够在所部署的真机上顺利运行,而对其中用到的几个比较重要的 NDK UI API 并没有仔细分析和学习,本着知其然也知其所以然的精神,本篇将就 H_ArkUI_NodeContent_AddNode、OH_ArkUI_NodeContent_RemoveNode 和 setAttribute 进行仔细的剖析,从而彻底认识和掌握。
一、UI 节点的增删
在使用 ArkTS 代码实现应用UI时,并不需要对 UI 树上的节点进行管理,一切交给 ArkTS 编译器自行处理,然而,到了 C++ 代码这边,却需要手动进行节点的挂载和移除,这一点,本人认为跟C++ UI 组件是通过 ContentSlot 去载入到 ArkTS Pages 的方式有关;具体什么缘故,暂且不论,因为目前也没有更底层的鸿蒙系统API源码可以跟踪,所以还是将目光放到C++代码中,如何手动管理节点的挂载和移除。
1、挂载节点
调用 NDK UI 组件也即由C++代码实现的UI组件时,需要将该组件对应的根节点(相当于用@Compoment装饰的 ArkTS 结构体)挂载到UI树上,从而才能在应用视图中渲染;这一步,在上一篇的案例代码中,就是 NativeEntry 类的 setRootNode 方法:
void SetRootNode(const std::shared_ptr<NativeModule::ArkUIBaseNode> &root) {
root_ = root;
// 添加 Native 组件到 NodeContent 上用于挂载显示
OH_ArkUI_NodeContent_AddNode(handle_, root_->GetHandle());
}
该方法体的实现,也就两行代码,第一行代码就是将参数传进来的指针,赋值给私有变量进行持有,与所谓的挂载UI节点没有一毛钱关系,与此密切相关的也只能是剩下的一行代码,而 OH_ArkUI_NodeContent_AddNode 也真就是 NDK 提供的管理 UI 节点的 API。
2、OH_ArkUI_NodeContent_AddNode
该 API 原型如下:
方法的调用,必须传入两个规定类型的参数,对于第一个参数、也即 ArkUI_NodeContentHandle 对象实例,顺着案例的代码调用链,会在 NativeListPage.ets 里面看到实际传入的,就是 NodeContent 对象:
而 NodeContent:
而第二个参数,在案例代码里面,就是在 CreateTextListExample 方法中用 std::make_shared 包装创建的 ArkUIListNode 对象。
对于 std::make_shared,是 NDK 提供的标准库中用于创建动态对象的智能指针工具,从而保障指针安全;至于 ArkUIListNode 就是我们自己用 C++ 代码定义和实现的、代表列表组件的节点对象:
节点的具体创建,是通过调用 NDK API createNode 去完成的,而 createNode 功能主要就是根据参数类型创建相应的鸿蒙UI组件:
而 ArkUI_NodeType 现有如下:
/**
* @brief Enumerates ArkUI component types that can be created on the native side.
*
* @since 12
*/
typedef enum {
/** Custom node. */
ARKUI_NODE_CUSTOM = 0,
/** Text. */
ARKUI_NODE_TEXT = 1,
/** Text span. */
ARKUI_NODE_SPAN = 2,
/** Image span. */
ARKUI_NODE_IMAGE_SPAN = 3,
/** Image. */
ARKUI_NODE_IMAGE = 4,
/** Toggle. */
ARKUI_NODE_TOGGLE = 5,
/** Loading icon. */
ARKUI_NODE_LOADING_PROGRESS = 6,
/** Single-line text input. */
ARKUI_NODE_TEXT_INPUT = 7,
/** Multi-line text input. */
ARKUI_NODE_TEXT_AREA = 8,
/** Button. */
ARKUI_NODE_BUTTON = 9,
/** Progress indicator. */
ARKUI_NODE_PROGRESS = 10,
/** Check box. */
ARKUI_NODE_CHECKBOX = 11,
/** XComponent. */
ARKUI_NODE_XCOMPONENT = 12,
/** Date picker. */
ARKUI_NODE_DATE_PICKER = 13,
/** Time picker. */
ARKUI_NODE_TIME_PICKER = 14,
/** Text picker. */
ARKUI_NODE_TEXT_PICKER = 15,
/** Calendar picker. */
ARKUI_NODE_CALENDAR_PICKER = 16,
/** Slider. */
ARKUI_NODE_SLIDER = 17,
/** Radio */
ARKUI_NODE_RADIO = 18,
/** Image animator. */
ARKUI_NODE_IMAGE_ANIMATOR = 19,
/** XComponent of type TEXTURE.
* @since 18
*/
ARKUI_NODE_XCOMPONENT_TEXTURE,
/** Check box group.
* @since 15
*/
ARKUI_NODE_CHECKBOX_GROUP = 21,
/** Stack container. */
ARKUI_NODE_STACK = MAX_NODE_SCOPE_NUM,
/** Swiper. */
ARKUI_NODE_SWIPER,
/** Scrolling container. */
ARKUI_NODE_SCROLL,
/** List. */
ARKUI_NODE_LIST,
/** List item. */
ARKUI_NODE_LIST_ITEM,
/** List item group. */
ARKUI_NODE_LIST_ITEM_GROUP,
/** Column container. */
ARKUI_NODE_COLUMN,
/** Row container. */
ARKUI_NODE_ROW,
/** Flex container. */
ARKUI_NODE_FLEX,
/** Refresh component. */
ARKUI_NODE_REFRESH,
/** Water flow container. */
ARKUI_NODE_WATER_FLOW,
/** Water flow item. */
ARKUI_NODE_FLOW_ITEM,
/** Relative layout component. */
ARKUI_NODE_RELATIVE_CONTAINER,
/** Grid. */
ARKUI_NODE_GRID,
/** Grid item. */
ARKUI_NODE_GRID_ITEM,
/** Custom span. */
ARKUI_NODE_CUSTOM_SPAN,
/**
* EmbeddedComponent.
* @since 20
*/
ARKUI_NODE_EMBEDDED_COMPONENT,
/**
* Undefined.
* @since 20
*/
ARKUI_NODE_UNDEFINED,
} ArkUI_NodeType;
因此,在C++代码中要创建一个具体的鸿蒙UI组件类型的节点,只需按着ArkUI_NodeType这个图去索骥即可。
3、移除节点
移除节点,在上一篇的案例代码中,是在 NativeEntry 类的 DisposeRootNode 方法中,调用 NDK API OH_ArkUI_NodeContent_RemoveNode 去完成的,该API方法原型如下:
是与 OH_ArkUI_NodeContent_AddNode() 相互配合使用的,参数结构也与 OH_ArkUI_NodeContent_AddNode() 如出一辙,所以,可以直接参考前面的内容去认识和掌握它即可。
二、节点属性的设置
如果屏幕前的你已经仔细阅读上一篇的案例代码,不难发现,无论是 ArkUINode,还是 ArkUIListNode 和 ArkUIListItemNode,亦或是 ArkUITextNode,设置节点属性的实现代码是用同一个模子刻出来的:
大家都关键地用到了 setAttribute 这个 NDK API:
1、ArkUI_NodeAttributeType
ArkUI_NodeAttributeType 定义的字段比较多,具体的可以到这里进行浏览。
这些属性,分为组件公共属性,也就是类似 NODE_WIDTH 这种名称不带具体组件称呼的;以及组件私有属性,如 NODE_LIST_ALIGN_LIST_ITEM 带着具体组件名称的。
ArkUI_NodeAttributeType 就是用来告诉 setAttribute 方法,参数一具体是什么类型的组件、以及即将要对该类型组件的哪个属性进行设置。
2、ArkUI_AttributeItem
setAttribute 方法的第三个参数,是一个 ArkUI_AttributeItem 类型的常指针。
ArkUI_AttributeItem 的原型如下:
**
* @brief Defines the general input parameter structure of the {@link setAttribute} function.
*
* @since 12
*/
typedef struct {
/** Numeric array. */
const ArkUI_NumberValue* value;
/** Size of the numeric array. */
int32_t size;
/** String type. */
const char* string;
/** Object type. */
void* object;
} ArkUI_AttributeItem;
也只有看了这个ArkUI_AttributeItem原型,才会明白 ArkUI_NumberValue value[] = {{.i32 = align}}; 和 ArkUI_AttributeItem item = {value, 1}; 这两行代码的具体意义。
ArkUI_NumberValue 实际上也是一个结构体:
/**
* @brief Provides the number types of ArkUI in the native code.
*
* @since 12
*/
typedef union {
/** Floating-point type. */
float f32;
/** Signed integer. */
int32_t i32;
/** Unsigned integer. */
uint32_t u32;
} ArkUI_NumberValue;
表示数字类型,具体的值对应什么类型,就给对应的字段进行赋值,所以 ArkUI_NumberValue value[] = {{.i32 = align}} 就是设置一个 int32_t 类型的数字值。
通常,如果设置节点属性所用的数据值是数字类型的,那么只需对 ArkUI_AttributeItem 的前两个字段进行赋值;而如果是字符串类型的,那么就需要用类似 ArkUI_AttributeItem item = {nullptr, 0, content.c_str()} 代码,将最后两个字段也进行赋值,并且代表数字的前两个字段要分别设置为 nullptr 和 0——表示空值。
浙公网安备 33010602011771号