1e41f4b71Sopenharmony_ci# Building Custom Components 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci 4e41f4b71Sopenharmony_ciThe ArkUI development framework provides capabilities for creating custom UI components through NDK APIs, including custom measurement, layout, and drawing. You can integrate into ArkUI's layout and rendering process by registering custom callback events using the [registerNodeCustomEvent](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#registernodecustomevent) function and adding custom event listeners for components with the [addNodeCustomEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addnodecustomeventreceiver) function. The logic for custom measurement, layout, and drawing is handled within the callback functions of these listeners. 5e41f4b71Sopenharmony_ci 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci> **NOTE** 8e41f4b71Sopenharmony_ci> 9e41f4b71Sopenharmony_ci> - Custom component event registration requires [addNodeCustomEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addnodecustomeventreceiver) to declare the listener registration and registerNodeCustomEvent](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#registernodecustomevent) to declare the required custom event types; listeners can only listen to declared events. 10e41f4b71Sopenharmony_ci> 11e41f4b71Sopenharmony_ci> - IPay attention to the logic of event deregistration, such as calling [removeNodeCustomEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#removenodecustomeventreceiver) to remove the event listener before the component is destroyed, and [unregisterNodeCustomEvent](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#unregisternodecustomevent) to notify the ArkUI framework that the custom component events that have been listened to are no longer needed. 12e41f4b71Sopenharmony_ci> 13e41f4b71Sopenharmony_ci> - [addNodeCustomEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addnodecustomeventreceiver) can add multiple function pointers, each of which is triggered when the corresponding event occurs. To remove a listener, the corresponding [removeNodeCustomEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#removenodecustomeventreceiver) function must be called with the exact function pointer used for adding the listener. 14e41f4b71Sopenharmony_ci> 15e41f4b71Sopenharmony_ci> - [registerNodeCustomEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#registernodecustomeventreceiver) is a global event listener function. Unlike [addNodeCustomEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addnodecustomeventreceiver), **registerNodeCustomEventReceiver** can listen for the event triggers of all native components, but it can only accept a single function pointer. If it is called multiple times, only the last function pointer provided will be used for callbacks. To release the listener, use the **unregisterNodeCustomEventReceiver** function. 16e41f4b71Sopenharmony_ci> 17e41f4b71Sopenharmony_ci> - Custom component-related APIs ([measureNode](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#measurenode), [layoutNode](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#layoutnode), [setMeasuredSize](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#setmeasuredsize), [setLayoutPosition](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#setlayoutposition)) can only be used in the corresponding custom event callbacks ([ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE, ARKUI_NODE_CUSTOM_EVENT_ON_LAYOUT](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodecustomeventtype)). 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ci## Custom Layout Container 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ciThe following example creates a custom container that uses the maximum size of its child components, plus additional padding, as its own size, while center-aligning the child components. 23e41f4b71Sopenharmony_ci 24e41f4b71Sopenharmony_ci**Figure 1** Custom container component 25e41f4b71Sopenharmony_ci 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci1. Follow the instructions in [Integrating with ArkTS Pages](ndk-access-the-arkts-page.md) to create a project. 29e41f4b71Sopenharmony_ci 30e41f4b71Sopenharmony_ci2. Create an encapsulated object for the custom container component. 31e41f4b71Sopenharmony_ci ```c 32e41f4b71Sopenharmony_ci // ArkUICustomContainerNode.h 33e41f4b71Sopenharmony_ci // Example of a custom container component 34e41f4b71Sopenharmony_ci 35e41f4b71Sopenharmony_ci #ifndef MYAPPLICATION_ARKUICUSTOMCONTAINERNODE_H 36e41f4b71Sopenharmony_ci #define MYAPPLICATION_ARKUICUSTOMCONTAINERNODE_H 37e41f4b71Sopenharmony_ci 38e41f4b71Sopenharmony_ci #include "ArkUINode.h" 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ci namespace NativeModule { 41e41f4b71Sopenharmony_ci 42e41f4b71Sopenharmony_ci class ArkUICustomContainerNode : public ArkUINode { 43e41f4b71Sopenharmony_ci public: 44e41f4b71Sopenharmony_ci // Create the component using the custom component type ARKUI_NODE_CUSTOM. 45e41f4b71Sopenharmony_ci ArkUICustomContainerNode() 46e41f4b71Sopenharmony_ci : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_CUSTOM)) { 47e41f4b71Sopenharmony_ci // Register the custom event listener. 48e41f4b71Sopenharmony_ci nativeModule_->addNodeCustomEventReceiver(handle_, OnStaticCustomEvent); 49e41f4b71Sopenharmony_ci // Declare the custom event and pass itself as custom data. 50e41f4b71Sopenharmony_ci nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE, 0, this); 51e41f4b71Sopenharmony_ci nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_LAYOUT, 0, this); 52e41f4b71Sopenharmony_ci } 53e41f4b71Sopenharmony_ci 54e41f4b71Sopenharmony_ci ~ArkUICustomContainerNode() override { 55e41f4b71Sopenharmony_ci // Deregister the custom event listener. 56e41f4b71Sopenharmony_ci nativeModule_->removeNodeCustomEventReceiver(handle_, OnStaticCustomEvent); 57e41f4b71Sopenharmony_ci // Undeclare the custom event. 58e41f4b71Sopenharmony_ci nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE); 59e41f4b71Sopenharmony_ci nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_LAYOUT); 60e41f4b71Sopenharmony_ci } 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ci void SetPadding(int32_t padding) { 63e41f4b71Sopenharmony_ci padding_ = padding; 64e41f4b71Sopenharmony_ci // To update a custom property event, you need to proactively call the API for marking the dirty region. 65e41f4b71Sopenharmony_ci nativeModule_->markDirty(handle_, NODE_NEED_MEASURE); 66e41f4b71Sopenharmony_ci } 67e41f4b71Sopenharmony_ci 68e41f4b71Sopenharmony_ci private: 69e41f4b71Sopenharmony_ci static void OnStaticCustomEvent(ArkUI_NodeCustomEvent *event) { 70e41f4b71Sopenharmony_ci // Obtain the component instance object and call the related instance method. 71e41f4b71Sopenharmony_ci auto customNode = reinterpret_cast<ArkUICustomContainerNode *>(OH_ArkUI_NodeCustomEvent_GetUserData(event)); 72e41f4b71Sopenharmony_ci auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event); 73e41f4b71Sopenharmony_ci switch (type) { 74e41f4b71Sopenharmony_ci case ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE: 75e41f4b71Sopenharmony_ci customNode->OnMeasure(event); 76e41f4b71Sopenharmony_ci break; 77e41f4b71Sopenharmony_ci case ARKUI_NODE_CUSTOM_EVENT_ON_LAYOUT: 78e41f4b71Sopenharmony_ci customNode->OnLayout(event); 79e41f4b71Sopenharmony_ci break; 80e41f4b71Sopenharmony_ci default: 81e41f4b71Sopenharmony_ci break; 82e41f4b71Sopenharmony_ci } 83e41f4b71Sopenharmony_ci } 84e41f4b71Sopenharmony_ci 85e41f4b71Sopenharmony_ci // Custom measurement logic. 86e41f4b71Sopenharmony_ci void OnMeasure(ArkUI_NodeCustomEvent *event) { 87e41f4b71Sopenharmony_ci auto layoutConstrain = OH_ArkUI_NodeCustomEvent_GetLayoutConstraintInMeasure(event); 88e41f4b71Sopenharmony_ci // Create child node layout constraints, reusing the percentage reference values in the parent component layout. 89e41f4b71Sopenharmony_ci auto childLayoutConstrain = OH_ArkUI_LayoutConstraint_Copy(layoutConstrain); 90e41f4b71Sopenharmony_ci OH_ArkUI_LayoutConstraint_SetMaxHeight(childLayoutConstrain, 1000); 91e41f4b71Sopenharmony_ci OH_ArkUI_LayoutConstraint_SetMaxWidth(childLayoutConstrain, 1000); 92e41f4b71Sopenharmony_ci OH_ArkUI_LayoutConstraint_SetMinHeight(childLayoutConstrain, 0); 93e41f4b71Sopenharmony_ci OH_ArkUI_LayoutConstraint_SetMinWidth(childLayoutConstrain, 0); 94e41f4b71Sopenharmony_ci 95e41f4b71Sopenharmony_ci // Measure the child nodes to get the maximum values. 96e41f4b71Sopenharmony_ci auto totalSize = nativeModule_->getTotalChildCount(handle_); 97e41f4b71Sopenharmony_ci int32_t maxWidth = 0; 98e41f4b71Sopenharmony_ci int32_t maxHeight = 0; 99e41f4b71Sopenharmony_ci for (uint32_t i = 0; i < totalSize; i++) { 100e41f4b71Sopenharmony_ci auto child = nativeModule_->getChildAt(handle_, i); 101e41f4b71Sopenharmony_ci // Call the measurement API to measure the native component. 102e41f4b71Sopenharmony_ci nativeModule_->measureNode(child, childLayoutConstrain); 103e41f4b71Sopenharmony_ci auto size = nativeModule_->getMeasuredSize(child); 104e41f4b71Sopenharmony_ci if (size.width > maxWidth) { 105e41f4b71Sopenharmony_ci maxWidth = size.width; 106e41f4b71Sopenharmony_ci } 107e41f4b71Sopenharmony_ci if (size.height > maxHeight) { 108e41f4b71Sopenharmony_ci maxHeight = size.height; 109e41f4b71Sopenharmony_ci } 110e41f4b71Sopenharmony_ci } 111e41f4b71Sopenharmony_ci // Custom measurement is the sum of all child node sizes plus a fixed margin. 112e41f4b71Sopenharmony_ci nativeModule_->setMeasuredSize(handle_, maxWidth + 2 * padding_, maxHeight + 2 * padding_); 113e41f4b71Sopenharmony_ci } 114e41f4b71Sopenharmony_ci 115e41f4b71Sopenharmony_ci void OnLayout(ArkUI_NodeCustomEvent *event) { 116e41f4b71Sopenharmony_ci // Obtain the desired position of the parent component and set it. 117e41f4b71Sopenharmony_ci auto position = OH_ArkUI_NodeCustomEvent_GetPositionInLayout(event); 118e41f4b71Sopenharmony_ci nativeModule_->setLayoutPosition(handle_, position.x, position.y); 119e41f4b71Sopenharmony_ci 120e41f4b71Sopenharmony_ci // Set child components to be center-aligned. 121e41f4b71Sopenharmony_ci auto totalSize = nativeModule_->getTotalChildCount(handle_); 122e41f4b71Sopenharmony_ci auto selfSize = nativeModule_->getMeasuredSize(handle_); 123e41f4b71Sopenharmony_ci for (uint32_t i = 0; i < totalSize; i++) { 124e41f4b71Sopenharmony_ci auto child = nativeModule_->getChildAt(handle_, i); 125e41f4b71Sopenharmony_ci // Obtain the child component size. 126e41f4b71Sopenharmony_ci auto childSize = nativeModule_->getMeasuredSize(child); 127e41f4b71Sopenharmony_ci // Lay out the child components. 128e41f4b71Sopenharmony_ci nativeModule_->layoutNode(child, (selfSize.width - childSize.width) / 2, 129e41f4b71Sopenharmony_ci (selfSize.height - childSize.height) / 2); 130e41f4b71Sopenharmony_ci } 131e41f4b71Sopenharmony_ci } 132e41f4b71Sopenharmony_ci 133e41f4b71Sopenharmony_ci int32_t padding_ = 100; 134e41f4b71Sopenharmony_ci }; 135e41f4b71Sopenharmony_ci 136e41f4b71Sopenharmony_ci } // namespace NativeModule 137e41f4b71Sopenharmony_ci 138e41f4b71Sopenharmony_ci #endif // MYAPPLICATION_ARKUICUSTOMCONTAINERNODE_H 139e41f4b71Sopenharmony_ci ``` 140e41f4b71Sopenharmony_ci 141e41f4b71Sopenharmony_ci3. Use the custom container to create a sample UI with text, and continue with the [timer module simple implementation](ndk-loading-long-list.md). 142e41f4b71Sopenharmony_ci ```c 143e41f4b71Sopenharmony_ci // Custom NDK API entry point. 144e41f4b71Sopenharmony_ci 145e41f4b71Sopenharmony_ci #include "NativeEntry.h" 146e41f4b71Sopenharmony_ci 147e41f4b71Sopenharmony_ci #include "ArkUICustomContainerNode.h" 148e41f4b71Sopenharmony_ci #include "ArkUITextNode.h" 149e41f4b71Sopenharmony_ci 150e41f4b71Sopenharmony_ci #include <arkui/native_node_napi.h> 151e41f4b71Sopenharmony_ci #include <arkui/native_type.h> 152e41f4b71Sopenharmony_ci #include <js_native_api.h> 153e41f4b71Sopenharmony_ci 154e41f4b71Sopenharmony_ci namespace NativeModule { 155e41f4b71Sopenharmony_ci 156e41f4b71Sopenharmony_ci napi_value CreateNativeRoot(napi_env env, napi_callback_info info) { 157e41f4b71Sopenharmony_ci size_t argc = 1; 158e41f4b71Sopenharmony_ci napi_value args[1] = {nullptr}; 159e41f4b71Sopenharmony_ci 160e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 161e41f4b71Sopenharmony_ci 162e41f4b71Sopenharmony_ci // Obtain NodeContent. 163e41f4b71Sopenharmony_ci ArkUI_NodeContentHandle contentHandle; 164e41f4b71Sopenharmony_ci OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); 165e41f4b71Sopenharmony_ci NativeEntry::GetInstance()->SetContentHandle(contentHandle); 166e41f4b71Sopenharmony_ci 167e41f4b71Sopenharmony_ci // Create a custom container and text component. 168e41f4b71Sopenharmony_ci auto node = std::make_shared<ArkUICustomContainerNode>(); 169e41f4b71Sopenharmony_ci node->SetBackgroundColor(0xFFE0FFFF); 170e41f4b71Sopenharmony_ci auto textNode = std::make_shared<ArkUITextNode>(); 171e41f4b71Sopenharmony_ci textNode->SetTextContent("CustomContainer Example"); 172e41f4b71Sopenharmony_ci textNode->SetFontSize(16); 173e41f4b71Sopenharmony_ci textNode->SetBackgroundColor(0xFFfffacd); 174e41f4b71Sopenharmony_ci textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); 175e41f4b71Sopenharmony_ci node->AddChild(textNode); 176e41f4b71Sopenharmony_ci CreateNativeTimer(env, textNode.get(), 1, [](void *userData, int32_t count) { 177e41f4b71Sopenharmony_ci auto textNode = reinterpret_cast<ArkUITextNode *>(userData); 178e41f4b71Sopenharmony_ci textNode->SetCircleColor(0xFF00FF7F); 179e41f4b71Sopenharmony_ci }); 180e41f4b71Sopenharmony_ci 181e41f4b71Sopenharmony_ci // Keep the native side object in the management class to maintain its lifecycle. 182e41f4b71Sopenharmony_ci NativeEntry::GetInstance()->SetRootNode(node); 183e41f4b71Sopenharmony_ci g_env = env; 184e41f4b71Sopenharmony_ci return nullptr; 185e41f4b71Sopenharmony_ci } 186e41f4b71Sopenharmony_ci 187e41f4b71Sopenharmony_ci napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) { 188e41f4b71Sopenharmony_ci // Release the native side object from the management class. 189e41f4b71Sopenharmony_ci NativeEntry::GetInstance()->DisposeRootNode(); 190e41f4b71Sopenharmony_ci return nullptr; 191e41f4b71Sopenharmony_ci } 192e41f4b71Sopenharmony_ci 193e41f4b71Sopenharmony_ci } // namespace NativeModule 194e41f4b71Sopenharmony_ci ``` 195e41f4b71Sopenharmony_ci 196e41f4b71Sopenharmony_ci 197e41f4b71Sopenharmony_ci## Custom Drawing Component 198e41f4b71Sopenharmony_ci 199e41f4b71Sopenharmony_ciThe following example creates a custom drawing component that can draw a custom rectangle and uses the aforementioned custom container for layout arrangement. 200e41f4b71Sopenharmony_ci 201e41f4b71Sopenharmony_ci**Figure 2** Custom drawing component 202e41f4b71Sopenharmony_ci 203e41f4b71Sopenharmony_ci 204e41f4b71Sopenharmony_ci 205e41f4b71Sopenharmony_ci1. Prepare a project as instructed in [Custom Layout Container](#custom-layout-container). 206e41f4b71Sopenharmony_ci 207e41f4b71Sopenharmony_ci2. Create an encapsulated object for the custom drawing component. 208e41f4b71Sopenharmony_ci ```c 209e41f4b71Sopenharmony_ci // ArkUICustomNode.h 210e41f4b71Sopenharmony_ci // Example of a custom drawing component 211e41f4b71Sopenharmony_ci 212e41f4b71Sopenharmony_ci #ifndef MYAPPLICATION_ARKUICUSTOMNODE_H 213e41f4b71Sopenharmony_ci #define MYAPPLICATION_ARKUICUSTOMNODE_H 214e41f4b71Sopenharmony_ci 215e41f4b71Sopenharmony_ci #include <native_drawing/drawing_brush.h> 216e41f4b71Sopenharmony_ci #include <native_drawing/drawing_canvas.h> 217e41f4b71Sopenharmony_ci #include <native_drawing/drawing_path.h> 218e41f4b71Sopenharmony_ci 219e41f4b71Sopenharmony_ci #include "ArkUINode.h" 220e41f4b71Sopenharmony_ci 221e41f4b71Sopenharmony_ci namespace NativeModule { 222e41f4b71Sopenharmony_ci 223e41f4b71Sopenharmony_ci class ArkUICustomNode : public ArkUINode { 224e41f4b71Sopenharmony_ci public: 225e41f4b71Sopenharmony_ci // Create the component using the custom component type ARKUI_NODE_CUSTOM. 226e41f4b71Sopenharmony_ci ArkUICustomNode() 227e41f4b71Sopenharmony_ci : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_CUSTOM)) { 228e41f4b71Sopenharmony_ci // Register the custom event listener. 229e41f4b71Sopenharmony_ci nativeModule_->addNodeCustomEventReceiver(handle_, OnStaticCustomEvent); 230e41f4b71Sopenharmony_ci // Declare the custom event and pass itself as custom data. 231e41f4b71Sopenharmony_ci nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW, 0, this); 232e41f4b71Sopenharmony_ci } 233e41f4b71Sopenharmony_ci 234e41f4b71Sopenharmony_ci ~ArkUICustomNode() override { 235e41f4b71Sopenharmony_ci // Deregister the custom event listener. 236e41f4b71Sopenharmony_ci nativeModule_->removeNodeCustomEventReceiver(handle_, OnStaticCustomEvent); 237e41f4b71Sopenharmony_ci // Undeclare the custom event. 238e41f4b71Sopenharmony_ci nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW); 239e41f4b71Sopenharmony_ci } 240e41f4b71Sopenharmony_ci 241e41f4b71Sopenharmony_ci void SetRectColor(uint32_t color) { 242e41f4b71Sopenharmony_ci color_ = color; 243e41f4b71Sopenharmony_ci // Custom drawing property changes require proactive notification to the framework. 244e41f4b71Sopenharmony_ci nativeModule_->markDirty(handle_, NODE_NEED_RENDER); 245e41f4b71Sopenharmony_ci } 246e41f4b71Sopenharmony_ci 247e41f4b71Sopenharmony_ci private: 248e41f4b71Sopenharmony_ci static void OnStaticCustomEvent(ArkUI_NodeCustomEvent *event) { 249e41f4b71Sopenharmony_ci // Obtain the component instance object and call the related instance method. 250e41f4b71Sopenharmony_ci auto customNode = reinterpret_cast<ArkUICustomNode *>(OH_ArkUI_NodeCustomEvent_GetUserData(event)); 251e41f4b71Sopenharmony_ci auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event); 252e41f4b71Sopenharmony_ci switch (type) { 253e41f4b71Sopenharmony_ci case ARKUI_NODE_CUSTOM_EVENT_ON_DRAW: 254e41f4b71Sopenharmony_ci customNode->OnDraw(event); 255e41f4b71Sopenharmony_ci break; 256e41f4b71Sopenharmony_ci default: 257e41f4b71Sopenharmony_ci break; 258e41f4b71Sopenharmony_ci } 259e41f4b71Sopenharmony_ci } 260e41f4b71Sopenharmony_ci 261e41f4b71Sopenharmony_ci // Custom drawing logic 262e41f4b71Sopenharmony_ci void OnDraw(ArkUI_NodeCustomEvent *event) { 263e41f4b71Sopenharmony_ci auto drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event); 264e41f4b71Sopenharmony_ci // Obtain the graphics drawing object. 265e41f4b71Sopenharmony_ci auto drawCanvas = reinterpret_cast<OH_Drawing_Canvas *>(OH_ArkUI_DrawContext_GetCanvas(drawContext)); 266e41f4b71Sopenharmony_ci // Obtain the component size. 267e41f4b71Sopenharmony_ci auto size = OH_ArkUI_DrawContext_GetSize(drawContext); 268e41f4b71Sopenharmony_ci // Draw custom content. 269e41f4b71Sopenharmony_ci auto path = OH_Drawing_PathCreate(); 270e41f4b71Sopenharmony_ci OH_Drawing_PathMoveTo(path, size.width / 4, size.height / 4); 271e41f4b71Sopenharmony_ci OH_Drawing_PathLineTo(path, size.width * 3 / 4, size.height / 4); 272e41f4b71Sopenharmony_ci OH_Drawing_PathLineTo(path, size.width * 3 / 4, size.height * 3 / 4); 273e41f4b71Sopenharmony_ci OH_Drawing_PathLineTo(path, size.width / 4, size.height * 3 / 4); 274e41f4b71Sopenharmony_ci OH_Drawing_PathLineTo(path, size.width / 4, size.height / 4); 275e41f4b71Sopenharmony_ci OH_Drawing_PathClose(path); 276e41f4b71Sopenharmony_ci auto brush = OH_Drawing_BrushCreate(); 277e41f4b71Sopenharmony_ci OH_Drawing_BrushSetColor(brush, color_); 278e41f4b71Sopenharmony_ci OH_Drawing_CanvasAttachBrush(drawCanvas, brush); 279e41f4b71Sopenharmony_ci OH_Drawing_CanvasDrawPath(drawCanvas, path); 280e41f4b71Sopenharmony_ci // Release resources. 281e41f4b71Sopenharmony_ci OH_Drawing_BrushDestroy(brush); 282e41f4b71Sopenharmony_ci OH_Drawing_PathDestroy(path); 283e41f4b71Sopenharmony_ci } 284e41f4b71Sopenharmony_ci 285e41f4b71Sopenharmony_ci uint32_t color_ = 0xFFFFE4B5; 286e41f4b71Sopenharmony_ci }; 287e41f4b71Sopenharmony_ci 288e41f4b71Sopenharmony_ci } // namespace NativeModule 289e41f4b71Sopenharmony_ci 290e41f4b71Sopenharmony_ci #endif // MYAPPLICATION_ARKUICUSTOMNODE_H 291e41f4b71Sopenharmony_ci ``` 292e41f4b71Sopenharmony_ci 293e41f4b71Sopenharmony_ci3. Create a sample UI using the custom drawing component and the custom container, and continue with the [timer module simple implementation](ndk-loading-long-list.md). 294e41f4b71Sopenharmony_ci ```c 295e41f4b71Sopenharmony_ci // Custom NDK API entry point. 296e41f4b71Sopenharmony_ci 297e41f4b71Sopenharmony_ci #include "NativeEntry.h" 298e41f4b71Sopenharmony_ci 299e41f4b71Sopenharmony_ci #include "ArkUICustomContainerNode.h" 300e41f4b71Sopenharmony_ci #include "ArkUICustomNode.h" 301e41f4b71Sopenharmony_ci 302e41f4b71Sopenharmony_ci #include <arkui/native_node_napi.h> 303e41f4b71Sopenharmony_ci #include <arkui/native_type.h> 304e41f4b71Sopenharmony_ci #include <js_native_api.h> 305e41f4b71Sopenharmony_ci 306e41f4b71Sopenharmony_ci namespace NativeModule { 307e41f4b71Sopenharmony_ci 308e41f4b71Sopenharmony_ci napi_value CreateNativeRoot(napi_env env, napi_callback_info info) { 309e41f4b71Sopenharmony_ci size_t argc = 1; 310e41f4b71Sopenharmony_ci napi_value args[1] = {nullptr}; 311e41f4b71Sopenharmony_ci 312e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 313e41f4b71Sopenharmony_ci 314e41f4b71Sopenharmony_ci // Obtain NodeContent. 315e41f4b71Sopenharmony_ci ArkUI_NodeContentHandle contentHandle; 316e41f4b71Sopenharmony_ci OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); 317e41f4b71Sopenharmony_ci NativeEntry::GetInstance()->SetContentHandle(contentHandle); 318e41f4b71Sopenharmony_ci 319e41f4b71Sopenharmony_ci // Create a custom container and a custom drawing component. 320e41f4b71Sopenharmony_ci auto node = std::make_shared<ArkUICustomContainerNode>(); 321e41f4b71Sopenharmony_ci node->SetBackgroundColor(0xFFE0FFFF); 322e41f4b71Sopenharmony_ci auto customNode = std::make_shared<ArkUICustomNode>(); 323e41f4b71Sopenharmony_ci customNode->SetBackgroundColor(0xFFD3D3D3); 324e41f4b71Sopenharmony_ci customNode->SetWidth(150); 325e41f4b71Sopenharmony_ci customNode->SetHeight(150); 326e41f4b71Sopenharmony_ci node->AddChild(customNode); 327e41f4b71Sopenharmony_ci CreateNativeTimer(env, customNode.get(), 1, [](void *userData, int32_t count) { 328e41f4b71Sopenharmony_ci auto customNode = reinterpret_cast<ArkUICustomNode *>(userData); 329e41f4b71Sopenharmony_ci customNode->SetRectColor(0xFF00FF7F); 330e41f4b71Sopenharmony_ci }); 331e41f4b71Sopenharmony_ci 332e41f4b71Sopenharmony_ci // Keep the native side object in the management class to maintain its lifecycle. 333e41f4b71Sopenharmony_ci NativeEntry::GetInstance()->SetRootNode(node); 334e41f4b71Sopenharmony_ci g_env = env; 335e41f4b71Sopenharmony_ci return nullptr; 336e41f4b71Sopenharmony_ci } 337e41f4b71Sopenharmony_ci 338e41f4b71Sopenharmony_ci napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) { 339e41f4b71Sopenharmony_ci // Release the native side object from the management class. 340e41f4b71Sopenharmony_ci NativeEntry::GetInstance()->DisposeRootNode(); 341e41f4b71Sopenharmony_ci return nullptr; 342e41f4b71Sopenharmony_ci } 343e41f4b71Sopenharmony_ci 344e41f4b71Sopenharmony_ci } // namespace NativeModule 345e41f4b71Sopenharmony_ci 346e41f4b71Sopenharmony_ci ``` 347