• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 构建渲染节点
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @xiang-shouxing-->
5<!--Designer: @xiang-shouxing-->
6<!--Tester: @sally__-->
7<!--Adviser: @HelloCrease-->
8
9
10从API version 20开始,ArkUI开发框针对NDK接口,提供了直接构建渲染节点的能力,包括节点树操作、属性设置及含动画的自定义绘制。开发者通过调用渲染节点相关能力,可以绕过[registerNodeCustomEvent](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#registernodecustomevent)的测量布局过程,直接对节点进行绘制并调整其大小和位置。
11
12
13- **渲染节点树操作相关的能力** ,例如[OH_ArkUI_RenderNodeUtils_AddRenderNode](../reference/apis-arkui/capi-native-render-h.md#oh_arkui_rendernodeutils_addrendernode)、[OH_ArkUI_RenderNodeUtils_AddChild](../reference/apis-arkui/capi-native-render-h.md#oh_arkui_rendernodeutils_addchild)等接口用于编辑渲染节点树的结构。仅类型为ARKUI_NODE_CUSTOM且无其他子节点的自定义节点(加超链接到nativeNode)能够挂载渲染节点,且最多挂载一个渲染节点。即渲染节点以子树形式挂载在类型为ARKUI_NODE_CUSTOM的叶子自定义节点上。
14
15- **渲染节点属性设置的能力** ,详情请参考[函数](../reference/apis-arkui/capi-native-render-h.md#函数),查看当前渲染节点支持的属性能力。
16
17- **自定义绘制能力**,参考[OH_ArkUI_RenderNodeUtils_SetContentModifierOnDraw](../reference/apis-arkui/capi-native-render-h.md#oh_arkui_rendernodeutils_setcontentmodifierondraw)及其相关接口,同时可以通过[OH_ArkUI_RenderNodeUtils_SetFloatPropertyValue](../reference/apis-arkui/capi-native-render-h.md#oh_arkui_rendernodeutils_setfloatpropertyvalue)这一类绑定在ContentModifier的接口对自定义绘制的内容进行动态修改。
18
19
20
21## 节点挂载与基础属性设置
22
23以下示例创建了一个渲染节点,并进行了基础的节点挂载和属性设置操作。
24
251. 按照[接入ArkTS页面](ndk-access-the-arkts-page.md)创建前置工程。
26
272. 创建渲染节点能力对象。
28   ```c
29   // manager.cpp
30   // 自定义容器组件示例。
31   #include <arkui/native_animate.h>
32   #include <arkui/native_render.h>
33   #include <arkui/native_type.h>
34   #include <arkui/native_node_napi.h>
35   #include <bits/alltypes.h>
36
37   #include <string>
38
39   #include <arkui/native_interface.h>
40   #include <arkui/native_node.h>
41   #include <native_drawing/drawing_canvas.h>
42   #include <native_drawing/drawing_color.h>
43   #include <native_drawing/drawing_path.h>
44   #include <native_drawing/drawing_pen.h>
45
46   ArkUI_NodeHandle testRenderNode(ArkUI_NativeNodeAPI_1 *nodeAPI) {
47       // 创建CAPI原有容器逻辑。
48       ArkUI_NodeHandle scroll = nodeAPI->createNode(ARKUI_NODE_SCROLL);
49       ArkUI_NumberValue valueWidth[] = {400};
50       ArkUI_AttributeItem itemWidth = {valueWidth, sizeof(valueWidth) / sizeof(ArkUI_NumberValue)};
51       nodeAPI->setAttribute(scroll, NODE_WIDTH, &itemWidth);
52       ArkUI_NumberValue valueHeight[] = {600};
53       ArkUI_AttributeItem itemHeight = {valueHeight, sizeof(valueHeight) / sizeof(ArkUI_NumberValue)};
54       nodeAPI->setAttribute(scroll, NODE_HEIGHT, &itemHeight);
55       ArkUI_NodeHandle column = nodeAPI->createNode(ARKUI_NODE_COLUMN);
56       nodeAPI->setAttribute(column, NODE_WIDTH, &itemWidth);
57       nodeAPI->setAttribute(column, NODE_HEIGHT, &itemHeight);
58       ArkUI_NodeHandle text = nodeAPI->createNode(ARKUI_NODE_TEXT);
59       ArkUI_AttributeItem content = {.string = "黄色背景是C-API页面"};
60       nodeAPI->setAttribute(text, NODE_TEXT_CONTENT, &content);
61       nodeAPI->addChild(column, text);
62
63       // 创建RenderNode容器 -- NDK侧的Custom组件。
64       ArkUI_NodeHandle Custom = nodeAPI->createNode(ARKUI_NODE_CUSTOM);
65       valueWidth[0].f32 = 400;
66       nodeAPI->setAttribute(Custom, NODE_WIDTH, &itemWidth);
67       nodeAPI->setAttribute(Custom, NODE_HEIGHT, &itemWidth);
68       nodeAPI->addChild(column, Custom);
69
70       // 节点操作类接口 创建 - 挂载 - 构建树。
71       // 创建部分。
72       auto renderRootNode = OH_ArkUI_RenderNodeUtils_CreateNode();
73       auto firstChildRenderNode = OH_ArkUI_RenderNodeUtils_CreateNode();
74       auto secondChildRenderNode = OH_ArkUI_RenderNodeUtils_CreateNode();
75       auto thirdChildRenderNode = OH_ArkUI_RenderNodeUtils_CreateNode();
76
77       auto result = OH_ArkUI_RenderNodeUtils_AddRenderNode(Custom, renderRootNode);
78       if (result != ARKUI_ERROR_CODE_NO_ERROR) {
79           // 通过错误码判断根节点是否挂载成功。
80           return scroll;
81       }
82
83       OH_ArkUI_RenderNodeUtils_AddChild(renderRootNode, firstChildRenderNode);
84       OH_ArkUI_RenderNodeUtils_AddChild(renderRootNode, secondChildRenderNode);
85       OH_ArkUI_RenderNodeUtils_AddChild(renderRootNode, thirdChildRenderNode);
86
87       // 设置节点尺寸与位置。
88       OH_ArkUI_RenderNodeUtils_SetSize(renderRootNode, 500, 500);
89       OH_ArkUI_RenderNodeUtils_SetSize(firstChildRenderNode, 120, 120);
90       OH_ArkUI_RenderNodeUtils_SetSize(secondChildRenderNode, 120, 120);
91       OH_ArkUI_RenderNodeUtils_SetSize(thirdChildRenderNode, 120, 120);
92
93       OH_ArkUI_RenderNodeUtils_SetPosition(renderRootNode, 300, 100);
94       OH_ArkUI_RenderNodeUtils_SetPosition(firstChildRenderNode, 0, 0);
95       OH_ArkUI_RenderNodeUtils_SetPosition(secondChildRenderNode, 140, 140);
96       OH_ArkUI_RenderNodeUtils_SetPosition(thirdChildRenderNode, 280, 280);
97
98       // 设置颜色,方便通过颜色观察到节点的显示范围。
99       OH_ArkUI_RenderNodeUtils_SetBackgroundColor(renderRootNode, 0xFFFFFFFF);
100       OH_ArkUI_RenderNodeUtils_SetBackgroundColor(firstChildRenderNode, 0xFFFF0000); // R
101       OH_ArkUI_RenderNodeUtils_SetBackgroundColor(secondChildRenderNode, 0xFF00FF00); // G
102       OH_ArkUI_RenderNodeUtils_SetBackgroundColor(thirdChildRenderNode, 0xFF0000FF); // B
103
104       // 简单的属性设置示例。
105       OH_ArkUI_RenderNodeUtils_SetRotation(secondChildRenderNode, 45, 45, 0); // xy轴旋转45度,z轴旋转0度
106
107       // 边框属性实例。
108       auto styleOption = OH_ArkUI_RenderNodeUtils_CreateNodeBorderStyleOption();
109       OH_ArkUI_RenderNodeUtils_SetNodeBorderStyleOptionEdgeStyle(styleOption, ArkUI_BorderStyle::ARKUI_BORDER_STYLE_SOLID,
110                                                                  ArkUI_EdgeDirection::ARKUI_EDGE_DIRECTION_ALL);
111       OH_ArkUI_RenderNodeUtils_SetBorderStyle(firstChildRenderNode, styleOption);
112       // 结构体使用完成后,销毁释放内存。
113       OH_ArkUI_RenderNodeUtils_DisposeNodeBorderStyleOption(styleOption);
114       styleOption = nullptr;
115
116       auto widthOption = OH_ArkUI_RenderNodeUtils_CreateNodeBorderWidthOption();
117       OH_ArkUI_RenderNodeUtils_SetNodeBorderWidthOptionEdgeWidth(widthOption, 5,
118                                                                  ArkUI_EdgeDirection::ARKUI_EDGE_DIRECTION_ALL);
119       OH_ArkUI_RenderNodeUtils_SetBorderWidth(firstChildRenderNode, widthOption);
120       // 结构体使用完成后,销毁释放内存。
121       OH_ArkUI_RenderNodeUtils_DisposeNodeBorderWidthOption(widthOption);
122       widthOption = nullptr;
123
124       auto colorOption = OH_ArkUI_RenderNodeUtils_CreateNodeBorderColorOption();
125       OH_ArkUI_RenderNodeUtils_SetNodeBorderColorOptionEdgeColor(colorOption, 0xFF000000,
126                                                                  ArkUI_EdgeDirection::ARKUI_EDGE_DIRECTION_ALL);
127       result = OH_ArkUI_RenderNodeUtils_SetBorderColor(firstChildRenderNode, colorOption);
128       // 结构体使用完成后,销毁释放内存。
129       OH_ArkUI_RenderNodeUtils_DisposeNodeBorderColorOption(colorOption);
130       colorOption = nullptr;
131
132       nodeAPI->addChild(scroll, column);
133       return scroll;
134   }
135
136   napi_value Manager::CreateNativeNode(napi_env env, napi_callback_info info) {
137       if ((env == nullptr) || (info == nullptr)) {
138           return nullptr;
139       }
140       size_t argCnt = 2;
141       napi_value args[2] = {nullptr};
142       if (napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr) != napi_ok) {
143           OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Manager", "CreateNativeNode napi_get_cb_info failed");
144       }
145
146       if (argCnt != 2) {
147           napi_throw_type_error(env, NULL, "Wrong number of arguments");
148           return nullptr;
149       }
150       napi_valuetype valuetype;
151       if (napi_typeof(env, args[0], &valuetype) != napi_ok) {
152           napi_throw_type_error(env, NULL, "napi_typeof failed");
153           return nullptr;
154       }
155
156       if (valuetype != napi_string) {
157           napi_throw_type_error(env, NULL, "Wrong type of arguments");
158           return nullptr;
159       }
160
161       char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
162       constexpr uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
163       size_t length;
164       if (napi_get_value_string_utf8(env, args[0], idStr, idSize, &length) != napi_ok) {
165           napi_throw_type_error(env, NULL, "napi_get_value_int64 failed");
166           return nullptr;
167       }
168
169       auto manager = Manager::GetInstance();
170       if (manager == nullptr) {
171           return nullptr;
172       }
173
174       OH_NativeXComponent *component = manager->GetNativeXComponent(idStr);
175       if (component == nullptr) {
176           return nullptr;
177       }
178
179       ArkUI_NodeHandle xxxNode;
180       auto resultx = OH_ArkUI_NodeUtils_GetNodeHandleByUniqueId(3, &xxxNode);
181
182       resultx = OH_ArkUI_RunTaskInScope((ArkUI_ContextHandle)111, nullptr, nullptr);
183       auto *nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 *>(
184           OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));
185       if (nodeAPI != nullptr) {
186           if (nodeAPI->createNode != nullptr && nodeAPI->addChild != nullptr) {
187               ArkUI_NodeHandle testNode;
188               testNode = testRenderNode(nodeAPI);
189
190               OH_NativeXComponent_AttachNativeRootNode(component, testNode);
191           }
192       }
193       return nullptr;
194   }
195
196   ```
197
198
199## 自定义绘制及动画
200
201以下示例创建了一个渲染节点,调用自定义绘制能力并附加动画功能。
202
2031. 按照[接入ArkTS页面](ndk-access-the-arkts-page.md)创建前置工程。
204
2052. 创建渲染节点能力对象。
206   ```c
207   // manager.cpp
208   // 自定义容器组件示例。
209   #include <arkui/native_animate.h>
210   #include <arkui/native_render.h>
211   #include <arkui/native_type.h>
212   #include <arkui/native_node_napi.h>
213   #include <bits/alltypes.h>
214
215   #include <string>
216
217   #include <arkui/native_interface.h>
218   #include <arkui/native_node.h>
219   #include <native_drawing/drawing_canvas.h>
220   #include <native_drawing/drawing_color.h>
221   #include <native_drawing/drawing_path.h>
222   #include <native_drawing/drawing_pen.h>
223
224   ArkUI_NodeHandle testRenderNode2(ArkUI_NativeNodeAPI_1 *nodeAPI, ArkUI_ContextHandle context) {
225
226       ArkUI_NodeHandle scroll = nodeAPI->createNode(ARKUI_NODE_COLUMN);
227       ArkUI_NumberValue valueWidth[] = {400};
228       ArkUI_AttributeItem itemWidth = {valueWidth, sizeof(valueWidth) / sizeof(ArkUI_NumberValue)};
229       nodeAPI->setAttribute(scroll, NODE_WIDTH, &itemWidth);
230       ArkUI_NumberValue valueHeight[] = {600};
231       ArkUI_AttributeItem itemHeight = {valueHeight, sizeof(valueHeight) / sizeof(ArkUI_NumberValue)};
232       nodeAPI->setAttribute(scroll, NODE_HEIGHT, &itemHeight);
233       valueHeight[0].u32 = 0xff00F100;
234       nodeAPI->setAttribute(scroll, NODE_BACKGROUND_COLOR, &itemHeight);
235
236       ArkUI_NodeHandle column = nodeAPI->createNode(ARKUI_NODE_COLUMN);
237       ArkUI_NodeHandle text = nodeAPI->createNode(ARKUI_NODE_TEXT);
238       ArkUI_AttributeItem content = {.string = "这是C-API页面"};
239
240       nodeAPI->setAttribute(text, NODE_TEXT_CONTENT, &content);
241
242       ArkUI_NodeHandle Custom = nodeAPI->createNode(ARKUI_NODE_CUSTOM);
243       auto renderNode = OH_ArkUI_RenderNodeUtils_CreateNode();
244       OH_ArkUI_RenderNodeUtils_AddRenderNode(Custom, renderNode);
245       OH_ArkUI_RenderNodeUtils_SetSize(renderNode, 1000, 1000);
246
247       // Property的作用是触发set更新,同步更新modifier的Draw方法。
248       struct AnimatableUserData {
249           ArkUI_FloatAnimatablePropertyHandle width;
250           ArkUI_FloatAnimatablePropertyHandle height;
251           ArkUI_Vector2AnimatablePropertyHandle v2;
252           ArkUI_ColorAnimatablePropertyHandle color;
253       };
254
255       // 设置基础值。
256       AnimatableUserData *userData1 = new AnimatableUserData;
257       auto widthAnimProperty = OH_ArkUI_RenderNodeUtils_CreateFloatAnimatableProperty(1000);
258       userData1->width = widthAnimProperty;
259       auto heightAnimProperty = OH_ArkUI_RenderNodeUtils_CreateFloatAnimatableProperty(1000);
260       userData1->height = heightAnimProperty;
261       auto vectorAnimP = OH_ArkUI_RenderNodeUtils_CreateVector2AnimatableProperty(1000, 1000);
262       userData1->v2 = vectorAnimP;
263       auto colorAnimP = OH_ArkUI_RenderNodeUtils_CreateColorAnimatableProperty(0xFFFF11FF);
264       userData1->color = colorAnimP;
265
266       // 关联组件和多个modifier。
267       auto animModifier = OH_ArkUI_RenderNodeUtils_CreateContentModifier();
268       OH_ArkUI_RenderNodeUtils_AttachContentModifier(renderNode, animModifier);
269       // 关联modifier和property。
270       OH_ArkUI_RenderNodeUtils_AttachFloatAnimatableProperty(animModifier, widthAnimProperty);
271       OH_ArkUI_RenderNodeUtils_AttachFloatAnimatableProperty(animModifier, heightAnimProperty);
272       OH_ArkUI_RenderNodeUtils_AttachVector2AnimatableProperty(animModifier, vectorAnimP);
273       OH_ArkUI_RenderNodeUtils_AttachColorAnimatableProperty(animModifier, colorAnimP);
274
275       // 设置自定义绘制内容。
276       OH_ArkUI_RenderNodeUtils_SetContentModifierOnDraw(
277           animModifier, userData1, [](ArkUI_DrawContext *context, void *userData) {
278               AnimatableUserData *data = (AnimatableUserData *)userData;
279               float width = 0;
280               float height = 0;
281               uint32_t color = 0;
282               ArkUI_Vector2AnimatablePropertyHandle v2 = data->v2;
283               // property主要为传值用,这里用x,y来替代width,实际使用时可以通过property来自定义所需参数。
284               OH_ArkUI_RenderNodeUtils_GetVector2AnimatablePropertyValue(v2, &width, &height);
285               ArkUI_ColorAnimatablePropertyHandle cp = data->color;
286               OH_ArkUI_RenderNodeUtils_GetColorAnimatablePropertyValue(cp, &color);
287
288
289               auto *canvas1 = OH_ArkUI_DrawContext_GetCanvas(context);
290               OH_Drawing_Canvas *canvas = reinterpret_cast<OH_Drawing_Canvas *>(canvas1);
291               auto path = OH_Drawing_PathCreate();
292               OH_Drawing_PathMoveTo(path, width / 4, height / 4);
293               OH_Drawing_PathLineTo(path, width * 3 / 4, height / 4);
294               OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4);
295               OH_Drawing_PathLineTo(path, width / 4, height * 3 / 4);
296               OH_Drawing_PathLineTo(path, width / 4, height / 4);
297               OH_Drawing_PathClose(path);
298               auto pen = OH_Drawing_PenCreate();
299               OH_Drawing_PenSetWidth(pen, 10);
300               OH_Drawing_PenSetColor(pen, color);
301               OH_Drawing_CanvasAttachPen(canvas, pen);
302               OH_Drawing_CanvasDrawPath(canvas, path);
303           });
304
305       // 用户自定义参数。
306       ArkUI_ContextCallback *update = new ArkUI_ContextCallback;
307       update->userData = userData1;
308       update->callback = [](void *user) {
309           AnimatableUserData *data = (AnimatableUserData *)user;
310           OH_ArkUI_RenderNodeUtils_SetFloatAnimatablePropertyValue(data->width, 100);
311           OH_ArkUI_RenderNodeUtils_SetFloatAnimatablePropertyValue(data->height, 100);
312           OH_ArkUI_RenderNodeUtils_SetVector2AnimatablePropertyValue(data->v2, 100, 100);
313           OH_ArkUI_RenderNodeUtils_SetColorAnimatablePropertyValue(data->color, 0xFF0011FF);
314       };
315       // 执行对应的动画。
316       ArkUI_NativeAnimateAPI_1 *animateApi = nullptr;
317       OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_ANIMATE, ArkUI_NativeAnimateAPI_1, animateApi);
318
319       ArkUI_AnimateCompleteCallback *completeCallback = new ArkUI_AnimateCompleteCallback;
320       completeCallback->userData = userData1;
321       completeCallback->type = ARKUI_FINISH_CALLBACK_REMOVED;
322       completeCallback->callback = [](void *userData) {
323           AnimatableUserData *data = (AnimatableUserData *)userData;
324       };
325
326       ArkUI_AnimateOption *option = OH_ArkUI_AnimateOption_Create();
327       OH_ArkUI_AnimateOption_SetDuration(option, 2000);
328       OH_ArkUI_AnimateOption_SetTempo(option, 1.1);
329       OH_ArkUI_AnimateOption_SetCurve(option, ARKUI_CURVE_EASE);
330       OH_ArkUI_AnimateOption_SetDelay(option, 20);
331       OH_ArkUI_AnimateOption_SetIterations(option, 1);
332       OH_ArkUI_AnimateOption_SetPlayMode(option, ARKUI_ANIMATION_PLAY_MODE_REVERSE);
333       ArkUI_ExpectedFrameRateRange *range = new ArkUI_ExpectedFrameRateRange;
334       range->min = 10;
335       range->max = 120;
336       range->expected = 60;
337       OH_ArkUI_AnimateOption_SetExpectedFrameRateRange(option, range);
338           animateApi->animateTo(context, option, update, completeCallback);
339
340
341       nodeAPI->setAttribute(Custom, NODE_WIDTH, &itemWidth);
342       nodeAPI->setAttribute(Custom, NODE_HEIGHT, &itemHeight);
343
344       nodeAPI->addChild(column, text);
345       nodeAPI->addChild(column, Custom);
346       nodeAPI->addChild(scroll, column);
347       return scroll;
348   }
349
350   napi_value Manager::CreateNativeNode(napi_env env, napi_callback_info info) {
351       if ((env == nullptr) || (info == nullptr)) {
352           return nullptr;
353       }
354       size_t argCnt = 2;
355       napi_value args[2] = {nullptr};
356       if (napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr) != napi_ok) {
357           OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Manager", "CreateNativeNode napi_get_cb_info failed");
358       }
359
360       if (argCnt != 2) {
361           napi_throw_type_error(env, NULL, "Wrong number of arguments");
362           return nullptr;
363       }
364       napi_valuetype valuetype;
365       if (napi_typeof(env, args[0], &valuetype) != napi_ok) {
366           napi_throw_type_error(env, NULL, "napi_typeof failed");
367           return nullptr;
368       }
369
370       if (valuetype != napi_string) {
371           napi_throw_type_error(env, NULL, "Wrong type of arguments");
372           return nullptr;
373       }
374
375       char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
376       constexpr uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
377       size_t length;
378       if (napi_get_value_string_utf8(env, args[0], idStr, idSize, &length) != napi_ok) {
379           napi_throw_type_error(env, NULL, "napi_get_value_int64 failed");
380           return nullptr;
381       }
382
383       auto manager = Manager::GetInstance();
384       if (manager == nullptr) {
385           return nullptr;
386       }
387
388       OH_NativeXComponent *component = manager->GetNativeXComponent(idStr);
389       if (component == nullptr) {
390           return nullptr;
391       }
392
393       ArkUI_NodeHandle xxxNode;
394       auto resultx = OH_ArkUI_NodeUtils_GetNodeHandleByUniqueId(3, &xxxNode);
395
396       resultx = OH_ArkUI_RunTaskInScope((ArkUI_ContextHandle)111, nullptr, nullptr);
397       auto *nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 *>(
398           OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));
399       if (nodeAPI != nullptr) {
400           if (nodeAPI->createNode != nullptr && nodeAPI->addChild != nullptr) {
401               ArkUI_NodeHandle testNode;
402               // 获取ets测传入的context。
403               ArkUI_ContextHandle context = nullptr;
404               // 通过code 判断是否获取成功。
405               auto code = OH_ArkUI_GetContextFromNapiValue(env, args[1], &context);
406               testNode = testRenderNode2(nodeAPI, context);
407
408               OH_NativeXComponent_AttachNativeRootNode(component, testNode);
409           }
410       }
411       return nullptr;
412   }
413
414   ```
415