• 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
9NDK提供了自定义绘制节点的能力,通过以下接口,开发者可以实现基于NDK侧Custom节点的自绘制能力。
10
11## 自定义绘制内容
12
13当监听到注册的事件为绘制类型时,可通过自定义绘制功能执行绘制逻辑,自定义绘制的内容。
14> **说明:**
15> - 在事件注册过程中,需将事件注册为绘制事件(如ARKUI_NODE_CUSTOM_EVENT_ON_DRAW),通过查阅[ArkUI_NodeCustomEventType](../reference/apis-arkui/capi-native-node-h.md#arkui_nodecustomeventtype)枚举值,获取事件类型及含义。
16>
17> - 若需实现自定义绘制逻辑,应自定义UserData,并在事件注册时进行传递。
18
19以下场景基于[接入ArkTS页面](ndk-access-the-arkts-page.md)章节,创建前置工程。
20
21- 自定义节点的创建,通过ArkUI_NativeNodeAPI_1的create接口,传入ARKUI_NODE_CUSTOM创建自定义节点。
22    ```c++
23    auto customNode = nodeAPI->createNode(ARKUI_NODE_CUSTOM);
24    ```
25
26- 在事件注册时将自定义节点、事件类型(例如ARKUI_NODE_CUSTOM_EVENT_ON_FOREGROUND_DRAW,获取NDK接口支持的事件类型范围可通过查询[ArkUI_NodeCustomEventType](../reference/apis-arkui/capi-native-node-h.md#arkui_nodecustomeventtype)枚举值)、事件ID和UserData作为参数传入。
27    ```c++
28    //UserData
29    struct A {
30        int32_t a =6;
31        bool flag = true;
32        ArkUI_NodeHandle node;
33    };
34    A *a = new A;
35    a->node = customNode;
36    nodeAPI->registerNodeCustomEvent(customNode,ARKUI_NODE_CUSTOM_EVENT_ON_FOREGROUND_DRAW,1,a);
37    nodeAPI->registerNodeCustomEventReceiver([](ArkUI_NodeCustomEvent *event) {
38    //事件回调函数逻辑
39    });
40    ```
41
42- 在回调函数中,获取自定义事件的事件类型(通过[OH_ArkUI_NodeCustomEvent_GetEventType](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodecustomevent_geteventtype))、事件ID(通过[OH_ArkUI_NodeCustomEvent_GetEventTargetId](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodecustomevent_geteventtargetid)获取)、UserData(通过[OH_ArkUI_NodeCustomEvent_GetUserData](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodecustomevent_getuserdata)获取)进行判断,以执行不同的逻辑。
43
44    ```c++
45    auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event);
46    auto targetId = OH_ArkUI_NodeCustomEvent_GetEventTargetId(event);
47    auto userData =reinterpret_cast<A *>( OH_ArkUI_NodeCustomEvent_GetUserData(event));
48    ```
49
50- [OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodecustomevent_getdrawcontextindraw)通过自定义组件事件获取绘制上下文,并将其传入 [OH_ArkUI_DrawContext_GetCanvas](../reference/apis-arkui/capi-native-type-h.md#oh_arkui_drawcontext_getcanvas)中以获取绘制canvas指针,该指针随后转换为OH_Drawing_Canvas指针进行绘制。
51    ```c++
52    //获取自定义事件绘制的上下文。
53    auto *drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event);
54    //获取绘制canvas指针。
55    auto *canvas1 = OH_ArkUI_DrawContext_GetCanvas(drawContext);
56    //转换为OH_Drawing_Canvas指针进行绘制。
57    OH_Drawing_Canvas *canvas = reinterpret_cast<OH_Drawing_Canvas *>(canvas1);
58    //绘制逻辑。
59    int32_t width = 1000;
60    int32_t height = 1000;
61    auto path = OH_Drawing_PathCreate();
62    OH_Drawing_PathMoveTo(path, width / 4, height / 4);
63    OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4);
64    OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4);
65    OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4);
66    OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4);
67    OH_Drawing_PathClose(path);
68    auto pen = OH_Drawing_PenCreate();
69    OH_Drawing_PenSetWidth(pen, 10);
70    OH_Drawing_PenSetColor(pen, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));
71    OH_Drawing_CanvasAttachPen(canvas, pen);
72    OH_Drawing_CanvasDrawPath(canvas, path);
73    ```
74**内容绘制的完整示例:**
75
76```c++
77#include <arkui/native_interface.h>
78#include <arkui/native_node.h>
79#include <native_drawing/drawing_canvas.h>
80#include <native_drawing/drawing_color.h>
81#include <native_drawing/drawing_path.h>
82#include <native_drawing/drawing_pen.h>
83
84ArkUI_NodeHandle test_draw(ArkUI_NativeNodeAPI_1 *nodeAPI) {
85    //创建节点
86    auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN);
87    auto customNode = nodeAPI->createNode(ARKUI_NODE_CUSTOM);
88    ArkUI_NumberValue value[] = {480};
89    ArkUI_AttributeItem item = {value, 1};
90    //属性设置
91    nodeAPI->setAttribute(column, NODE_WIDTH, &item);
92    value[0].i32 = 720;
93    nodeAPI->setAttribute(column, NODE_HEIGHT, &item);
94    ArkUI_NumberValue NODE_WIDTH_value[] = {200};
95    ArkUI_AttributeItem NODE_WIDTH_Item[] = {NODE_WIDTH_value, 1};
96    ArkUI_NumberValue NODE_HEIGHT_value[] = {200};
97    ArkUI_AttributeItem NODE_HEIGHT_Item[] = {NODE_HEIGHT_value, 1};
98    ArkUI_NumberValue NODE_BACKGROUND_COLOR_item_value[] = {{.u32 = 0xFFFFFF00}};
99    ArkUI_AttributeItem NODE_BACKGROUND_COLOR_Item[] = {NODE_BACKGROUND_COLOR_item_value, 1};
100    //自定义UserData。
101    struct A {
102        int32_t a =6;
103        bool flag = true;
104        ArkUI_NodeHandle node;
105    };
106    A *a = new A;
107    a->node = customNode;
108    nodeAPI->setAttribute(customNode, NODE_WIDTH, NODE_WIDTH_Item);
109    nodeAPI->setAttribute(customNode, NODE_HEIGHT, NODE_HEIGHT_Item);
110    nodeAPI->setAttribute(customNode, NODE_BACKGROUND_COLOR, NODE_BACKGROUND_COLOR_Item);
111    //进行事件注册
112    nodeAPI->registerNodeCustomEvent(customNode,ARKUI_NODE_CUSTOM_EVENT_ON_FOREGROUND_DRAW,1,a);
113    //事件回调函数的编写
114    nodeAPI->registerNodeCustomEventReceiver([](ArkUI_NodeCustomEvent *event) {
115        //获取自定义事件的相关信息。
116        auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event);
117        auto targetId = OH_ArkUI_NodeCustomEvent_GetEventTargetId(event);
118        auto userData =reinterpret_cast<A *>( OH_ArkUI_NodeCustomEvent_GetUserData(event));
119        if (type == ARKUI_NODE_CUSTOM_EVENT_ON_FOREGROUND_DRAW && targetId == 1 && userData->flag) {
120            //获取自定义事件绘制的上下文。
121            auto *drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event);
122            //获取绘制canvas指针。
123            auto *canvas1 = OH_ArkUI_DrawContext_GetCanvas(drawContext);
124            //转换为OH_Drawing_Canvas指针进行绘制。
125            OH_Drawing_Canvas *canvas = reinterpret_cast<OH_Drawing_Canvas *>(canvas1);
126            int32_t width = 1000;
127            int32_t height = 1000;
128            auto path = OH_Drawing_PathCreate();
129            OH_Drawing_PathMoveTo(path, width / 4, height / 4);
130            OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4);
131            OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4);
132            OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4);
133            OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4);
134            OH_Drawing_PathClose(path);
135            auto pen = OH_Drawing_PenCreate();
136            OH_Drawing_PenSetWidth(pen, 10);
137            OH_Drawing_PenSetColor(pen, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));
138            OH_Drawing_CanvasAttachPen(canvas, pen);
139            OH_Drawing_CanvasDrawPath(canvas, path);
140        }
141    });
142    //自定义节点上树
143    nodeAPI->addChild(column, customNode);
144    return column;
145}
146```
147![自定义绘制](figures/自定义绘制.jpg)
148
149## 自定义绘制前景背景
150
151以下示例创建了一个自定义绘制组件,该绘制组件能够绘制自定义矩形,同时可以自定义绘制前景和背景,并使用[自定义布局容器](ndk-build-custom-components.md#自定义布局容器)进行布局排布。
152
1531. 按照[自定义布局容器](ndk-build-custom-components.md#自定义布局容器)章节准备前置工程。
154
1552. 创建自定义绘制组件封装对象。
156```c
157// ArkUICustomNode.h
158// 自定义绘制组件示例
159
160#ifndef MYAPPLICATION_ARKUICUSTOMNODE_H
161#define MYAPPLICATION_ARKUICUSTOMNODE_H
162
163#include <native_drawing/drawing_brush.h>
164#include <native_drawing/drawing_canvas.h>
165#include <native_drawing/drawing_path.h>
166
167#include "ArkUINode.h"
168
169namespace NativeModule {
170
171class ArkUICustomNode : public ArkUINode {
172public:
173    // 使用自定义组件类型ARKUI_NODE_CUSTOM创建组件。
174    ArkUICustomNode()
175        : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_CUSTOM)) {
176        // 注册自定义事件监听器。
177        nativeModule_->addNodeCustomEventReceiver(handle_, OnStaticCustomEvent);
178        // 声明自定义事件并转递自身作为自定义数据。
179        nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_FRONT, 0, this);
180        nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW, 0, this);
181        nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_BEHIND , 0, this);
182
183    }
184
185    ~ArkUICustomNode() override {
186        // 反注册自定义事件监听器。
187        nativeModule_->removeNodeCustomEventReceiver(handle_, OnStaticCustomEvent);
188        // 取消声明自定义事件。
189        nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_FRONT);
190        nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW);
191        nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_BEHIND);
192    }
193
194private:
195    static void OnStaticCustomEvent(ArkUI_NodeCustomEvent *event) {
196        // 获取组件实例对象,调用相关实例方法。
197        auto customNode = reinterpret_cast<ArkUICustomNode *>(OH_ArkUI_NodeCustomEvent_GetUserData(event));
198        auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event);
199        switch (type) {
200        case ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_BEHIND:
201            customNode->OnDrawBehind(event);
202            break;
203        case ARKUI_NODE_CUSTOM_EVENT_ON_DRAW:
204            customNode->OnDraw(event);
205            break;
206        case ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_FRONT:
207            customNode->OnDrawFront(event);
208            break;
209        default:
210            break;
211        }
212    }
213
214    // 自定义绘制逻辑。
215    void OnDrawBehind(ArkUI_NodeCustomEvent *event) {
216        auto drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event);
217        // 获取图形绘制对象。
218        auto drawCanvas = reinterpret_cast<OH_Drawing_Canvas *>(OH_ArkUI_DrawContext_GetCanvas(drawContext));
219        // 获取组件大小。
220        auto size = OH_ArkUI_DrawContext_GetSize(drawContext);
221        // 绘制自定义内容。
222        auto path = OH_Drawing_PathCreate();
223        OH_Drawing_PathMoveTo(path, size.width / 5, size.height / 5);
224        OH_Drawing_PathLineTo(path, size.width * 4 / 5, size.height / 5);
225        OH_Drawing_PathLineTo(path, size.width * 4 / 5, size.height * 4 / 5);
226        OH_Drawing_PathLineTo(path, size.width / 5, size.height * 4 / 5);
227        OH_Drawing_PathLineTo(path, size.width / 5, size.height / 5);
228        OH_Drawing_PathClose(path);
229        auto brush = OH_Drawing_BrushCreate();
230        OH_Drawing_BrushSetColor(brush, 0xFFF0FAFF);// 蓝白色
231        OH_Drawing_CanvasAttachBrush(drawCanvas, brush);
232        OH_Drawing_CanvasDrawPath(drawCanvas, path);
233        // 释放资源
234        OH_Drawing_BrushDestroy(brush);
235        OH_Drawing_PathDestroy(path);
236    }
237
238    void OnDraw(ArkUI_NodeCustomEvent *event) {
239        auto drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event);
240        // 获取图形绘制对象。
241        auto drawCanvas = reinterpret_cast<OH_Drawing_Canvas *>(OH_ArkUI_DrawContext_GetCanvas(drawContext));
242        // 获取组件大小。
243        auto size = OH_ArkUI_DrawContext_GetSize(drawContext);
244        // 绘制自定义内容。
245        auto path = OH_Drawing_PathCreate();
246        OH_Drawing_PathMoveTo(path, size.width / 4, size.height / 4);
247        OH_Drawing_PathLineTo(path, size.width * 3 / 4, size.height / 4);
248        OH_Drawing_PathLineTo(path, size.width * 3 / 4, size.height * 3 / 4);
249        OH_Drawing_PathLineTo(path, size.width / 4, size.height * 3 / 4);
250        OH_Drawing_PathLineTo(path, size.width / 4, size.height / 4);
251        OH_Drawing_PathClose(path);
252        auto brush = OH_Drawing_BrushCreate();
253        OH_Drawing_BrushSetColor(brush, 0xff2787D9);// 浅蓝色
254        OH_Drawing_CanvasAttachBrush(drawCanvas, brush);
255        OH_Drawing_CanvasDrawPath(drawCanvas, path);
256        // 释放资源
257        OH_Drawing_BrushDestroy(brush);
258        OH_Drawing_PathDestroy(path);
259    }
260
261    void OnDrawFront(ArkUI_NodeCustomEvent *event) {
262        auto drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event);
263        // 获取图形绘制对象。
264        auto drawCanvas = reinterpret_cast<OH_Drawing_Canvas *>(OH_ArkUI_DrawContext_GetCanvas(drawContext));
265        // 获取组件大小。
266        auto size = OH_ArkUI_DrawContext_GetSize(drawContext);
267        // 绘制自定义内容。
268        auto path = OH_Drawing_PathCreate();
269        OH_Drawing_PathMoveTo(path, size.width / 3, size.height / 3);
270        OH_Drawing_PathLineTo(path, size.width * 2 / 3, size.height / 3);
271        OH_Drawing_PathLineTo(path, size.width * 2 / 3, size.height * 2 / 3);
272        OH_Drawing_PathLineTo(path, size.width / 3, size.height * 2 / 3);
273        OH_Drawing_PathLineTo(path, size.width / 3, size.height / 3);
274        OH_Drawing_PathClose(path);
275        auto brush = OH_Drawing_BrushCreate();
276        OH_Drawing_BrushSetColor(brush, 0xFF004AAF);// 深蓝色
277        OH_Drawing_CanvasAttachBrush(drawCanvas, brush);
278        OH_Drawing_CanvasDrawPath(drawCanvas, path);
279        // 释放资源
280        OH_Drawing_BrushDestroy(brush);
281        OH_Drawing_PathDestroy(path);
282    }
283};
284
285} // namespace NativeModule
286
287#endif // MYAPPLICATION_ARKUICUSTOMNODE_H
288```
289
2903. 使用自定义绘制组件和自定义容器创建示例界面
291```c
292// ArkUICustomNode.cpp
293// 自定义NDK接口入口组件。
294
295#include <arkui/native_node_napi.h>
296#include <arkui/native_type.h>
297#include <js_native_api.h>
298
299#include "NativeEntry.h"
300#include "ArkUICustomContainerNode.h"
301#include "ArkUICustomNode.h"
302
303// 全局环境变量声明
304static napi_env g_env = nullptr;
305
306namespace NativeModule {
307
308napi_value CreateNativeRoot(napi_env env, napi_callback_info info) {
309    size_t argc = 1;
310    napi_value args[1] = {nullptr};
311
312    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
313
314    // 获取NodeContent
315    ArkUI_NodeContentHandle contentHandle;
316    OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);
317    NativeEntry::GetInstance()->SetContentHandle(contentHandle);
318
319    // 创建自定义容器和自定义绘制组件。
320    auto node = std::make_shared<ArkUICustomContainerNode>();
321    node->SetBackgroundColor(0xFFD5D5D5);// 浅灰色
322    auto customNode = std::make_shared<ArkUICustomNode>();
323    customNode->SetBackgroundColor(0xFF707070);// 深灰色
324    customNode->SetWidth(150);
325    customNode->SetHeight(150);
326    node->AddChild(customNode);
327
328    // 保持Native侧对象到管理类中,维护生命周期。
329    NativeEntry::GetInstance()->SetRootNode(node);
330    g_env = env;
331    return nullptr;
332}
333
334napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) {
335    // 从管理类中释放Native侧对象。
336    NativeEntry::GetInstance()->DisposeRootNode();
337    return nullptr;
338}
339
340} // namespace NativeModule
341```
342![customDrawLayer](figures/capiDrawLayer.jpg)