鸿蒙NEXT系列之精析NDK UI API(节点增删和属性设置)
精析NDK UI API(节点增删和属性设置)
- 〇、前言
- 一、UI 节点的增删
- 1、挂载节点
- 2、OH_ArkUI_NodeContent_AddNode
- 3、移除节点
- 二、节点属性的设置
- 1、ArkUI_NodeAttributeType
- 2、ArkUI_AttributeItem
〇、前言
在上一篇,重点是案例的完整实现,使代码达到能够在所部署的真机上顺利运行,而对其中用到的几个比较重要的 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——表示空值。