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 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