自定义绘制
=====

#### 概述

当某些组件本身的绘制内容不满足需求时，可使用组件自定义绘制功能，在原有组件基础上部分绘制、或者全部自行绘制，以达到预期效果。例如：独特的按钮形状、文字和图像混合的图标等。NDK提供了自定义绘制节点的能力，通过自定义绘制事件，开发者可以实现基于NDK侧[ArkUI\_NodeType](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodetype)中ARKUI\_NODE\_CUSTOM类型节点的自绘制能力。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/11/v3/D7u2HqZFRkmpX1uJK9np_Q/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260612T073317Z&HW-CC-Expire=86400&HW-CC-Sign=6C0E81ADA5F74F6AE09C5993C17A909407ECE8795EC93FF3D01827AFF2D219F1)

*   ArkTS的自定义绘制能力和示例请参考[自定义绘制修改器 (DrawModifier)](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-user-defined-extension-drawmodifier)。

#### 自定义绘制层级

自定义绘制提供了五个绘制层级，从低到高依次为：内容背景层（drawBehind）、内容层（drawContent）、内容前景层（drawFront）、前景层（drawForeground）和浮层（drawOverlay）。开发者可以根据需求选择合适的层级进行绘制。自定义绘制层级图如下所示。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/b0/v3/PY6ymiM0SvC2AbLkS_9HyQ/zh-cn_image_0000002594668220.png?HW-CC-KV=V1&HW-CC-Date=20260612T073317Z&HW-CC-Expire=86400&HW-CC-Sign=5138226644838B9EAA7ACDE8C0B44EA2204BDBD4E20C3B7BC73FCD3A1942F820)

开发者可以通过注册相应的事件类型来实现不同层级的自定义绘制，不同层级对应的枚举如下，NDK接口支持的事件类型范围请参考[ArkUI\_NodeCustomEventType](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodecustomeventtype)枚举值。

| 事件类型 | 说明 |
| :-- | :-- |
| ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_BEHIND | 自定义内容背景层绘制类型，从API version 20开始支持。 |
| ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW | 自定义内容层绘制类型。 |
| ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_FRONT | 自定义内容前景层绘制类型，从API version 20开始支持。 |
| ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_FOREGROUND\_DRAW | 自定义前景层绘制类型。 |
| ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_OVERLAY\_DRAW | 自定义浮层绘制类型。 |

#### \[h2\]内容层自定义绘制示例

本示例通过注册内容层绘制事件ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW在节点内容层绘制一条从左上区域到右下区域的对角线段，效果图如下。

以下场景基于[接入ArkTS页面](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ndk-access-the-arkts-page)章节，创建前置工程。内容绘制的完整示例请参考[NativeDrawPageSample](https://gitcode.com/HarmonyOS_Samples/guide-snippets/tree/master/ArkUISample/NativeType/NativeDrawPageSample)。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/da/v3/a77wiC25QJWLm9bhW4eq3Q/zh-cn_image_0000002594828198.jpg?HW-CC-KV=V1&HW-CC-Date=20260612T073317Z&HW-CC-Expire=86400&HW-CC-Sign=604E8A2BF601E473EE212044FB26AA8D36644544A770FD22592C25E0479EF922)

1.  通过[ArkUI\_NativeNodeAPI\_1](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-arkui-nativemodule-arkui-nativenodeapi-1)的[createNode](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-arkui-nativemodule-arkui-nativenodeapi-1#createnode)接口，传入[ArkUI\_NodeType](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodecustomeventtype)中的ARKUI\_NODE\_CUSTOM枚举值创建自定义节点。
    
    auto customNode = nodeAPI->createNode(ARKUI\_NODE\_CUSTOM);
    
2.  事件注册时将自定义节点、事件类型、事件ID和UserData作为参数传入。
    
    // UserData
    struct A {
        int32\_t a = 6;
        bool flag = true;
        ArkUI\_NodeHandle node;
    };
    A \*a = new A;
    a->node = customNode;
    // ...
    nodeAPI->registerNodeCustomEvent(customNode, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_FOREGROUND\_DRAW, 1, a);
    // 事件回调函数的编写
    nodeAPI->registerNodeCustomEventReceiver(\[\](ArkUI\_NodeCustomEvent \*event) {
        // 事件回调函数逻辑
        // ...
    });
    
3.  在回调函数中，通过[OH\_ArkUI\_NodeCustomEvent\_GetEventType](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#oh_arkui_nodecustomevent_geteventtype)获取自定义事件的事件类型，通过[OH\_ArkUI\_NodeCustomEvent\_GetEventTargetId](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#oh_arkui_nodecustomevent_geteventtargetid)获取事件ID，通过[OH\_ArkUI\_NodeCustomEvent\_GetUserData](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#oh_arkui_nodecustomevent_getuserdata)获取UserData，再根据事件类型和事件ID判断当前触发的是哪个绘制事件，从而执行对应的逻辑。
    
    auto type = OH\_ArkUI\_NodeCustomEvent\_GetEventType(event);
    auto targetId = OH\_ArkUI\_NodeCustomEvent\_GetEventTargetId(event);
    auto userData = reinterpret\_cast<A \*>(OH\_ArkUI\_NodeCustomEvent\_GetUserData(event));
    
4.  [OH\_ArkUI\_NodeCustomEvent\_GetDrawContextInDraw](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#oh_arkui_nodecustomevent_getdrawcontextindraw)通过自定义组件事件获取绘制上下文，并将其传入[OH\_ArkUI\_DrawContext\_GetCanvas](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-type-h#oh_arkui_drawcontext_getcanvas)以获取Canvas画布指针，该指针随后将转换为[OH\_Drawing\_Canvas](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-drawing-oh-drawing-canvas)指针进行绘制。
    
    // 获取自定义事件绘制的上下文。
    auto \*drawContext = OH\_ArkUI\_NodeCustomEvent\_GetDrawContextInDraw(event);
    // 获取Canvas指针。
    auto \*canvas1 = OH\_ArkUI\_DrawContext\_GetCanvas(drawContext);
    // 转换为OH\_Drawing\_Canvas指针进行绘制。
    OH\_Drawing\_Canvas \*canvas = reinterpret\_cast<OH\_Drawing\_Canvas \*>(canvas1);
    // 绘制逻辑。
    int32\_t width = SIZE\_1000;  // SIZE\_1000 = 1000
    int32\_t height = SIZE\_1000; // SIZE\_1000 = 1000
    auto path = OH\_Drawing\_PathCreate();
    OH\_Drawing\_PathMoveTo(path, width / SIZE\_4, height / SIZE\_4);                   // SIZE\_4 = 4
    OH\_Drawing\_PathLineTo(path, width \* SIZE\_3 / SIZE\_4, height \* SIZE\_3 / SIZE\_4); // SIZE\_3 = 3,SIZE\_4 = 4
    OH\_Drawing\_PathClose(path);
    auto pen = OH\_Drawing\_PenCreate();
    OH\_Drawing\_PenSetWidth(pen, SIZE\_10); // SIZE\_10 = 10
    OH\_Drawing\_PenSetColor(pen, OH\_Drawing\_ColorSetArgb(0xFF, 0x00, 0x4A, 0x4F));
    OH\_Drawing\_CanvasAttachPen(canvas, pen);
    OH\_Drawing\_CanvasDrawPath(canvas, path);
    

#### \[h2\]多层级绘制示例

以下示例创建了一个自定义绘制组件，实现自定义矩形绘制、自定义绘制内容前景层和内容背景层，并支持使用[自定义布局容器](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ndk-build-custom-components#自定义布局容器)进行布局排布。完整示例请参考[NativeNodeUtilsSample](https://gitcode.com/HarmonyOS_Samples/guide-snippets/tree/master/ArkUISample/NativeType/NativeNodeUtilsSample)。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/df/v3/Uq0TH9F7TaC9lsJwvJbWDA/zh-cn_image_0000002625187645.jpg?HW-CC-KV=V1&HW-CC-Date=20260612T073317Z&HW-CC-Expire=86400&HW-CC-Sign=749F1C4B978DC2E8C86283D4130A10FA0515BE554B99B58615D64C9929726188)

图中深蓝矩形为drawFront内容前景层，浅蓝色矩形为drawContent内容层，白色矩形为drawBehind内容背景层。三层的叠加关系用于验证多层级绘制顺序是否符合预期。

1.  按照[自定义布局容器](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ndk-build-custom-components#自定义布局容器)章节准备前置工程。
    
2.  创建自定义绘制组件封装对象。
    
    #ifndef MYAPPLICATION\_ARKUICUSTOMNODE\_H
    #define MYAPPLICATION\_ARKUICUSTOMNODE\_H
    
    #include <native\_drawing/drawing\_brush.h>
    #include <native\_drawing/drawing\_canvas.h>
    #include <native\_drawing/drawing\_path.h>
    
    #include "ArkUINode.h"
    
    namespace NativeModule {
    class ArkUICustomNode : public ArkUINode {
    public:
        // 使用自定义组件类型ARKUI\_NODE\_CUSTOM创建组件。
        ArkUICustomNode()
            : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI\_NODE\_CUSTOM))
        {
            // 注册自定义事件监听器。
            nativeModule\_->addNodeCustomEventReceiver(handle\_, OnStaticCustomEvent);
            // 声明自定义事件并转递自身作为自定义数据。
            nativeModule\_->registerNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_FRONT, 0, this);
            nativeModule\_->registerNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW, 0, this);
            nativeModule\_->registerNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_BEHIND, 0, this);
            // 绘制完成事件通知。
            OH\_ArkUI\_RegisterDrawCallbackOnNodeHandle(handle\_, nullptr, \[\](void\* userData) {});
        }
    
        ~ArkUICustomNode() override
        {
            // 反注册自定义事件监听器。
            nativeModule\_->removeNodeCustomEventReceiver(handle\_, OnStaticCustomEvent);
            // 取消声明自定义事件。
            nativeModule\_->unregisterNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_FRONT);
            nativeModule\_->unregisterNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW);
            nativeModule\_->unregisterNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_BEHIND);
            OH\_ArkUI\_UnregisterDrawCallbackOnNodeHandle(handle\_);
        }
    
    private:
        int32\_t NUM\_2 = 2;
        int32\_t NUM\_3 = 3;
        int32\_t NUM\_4 = 4;
        int32\_t NUM\_5 = 5;
        static void OnStaticCustomEvent(ArkUI\_NodeCustomEvent \*event)
        {
            // 获取组件实例对象，调用相关实例方法。
            // ...
            auto customNode = reinterpret\_cast<ArkUICustomNode \*>(OH\_ArkUI\_NodeCustomEvent\_GetUserData(event));
            auto type = OH\_ArkUI\_NodeCustomEvent\_GetEventType(event);
            switch (type) {
                // 绘制层级由低到高。
                case ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_BEHIND:
                    customNode->OnDrawBehind(event);
                    break;
                case ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW:
                    customNode->OnDraw(event);
                    break;
                case ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_FRONT:
                    customNode->OnDrawFront(event);
                    break;
                // ...
                default:
                    break;
            }
        }
    
        // 自定义绘制逻辑。
        void OnDrawBehind(ArkUI\_NodeCustomEvent \*event)
        {
            auto drawContext = OH\_ArkUI\_NodeCustomEvent\_GetDrawContextInDraw(event);
            // 获取图形绘制对象。
            auto drawCanvas = reinterpret\_cast<OH\_Drawing\_Canvas \*>(OH\_ArkUI\_DrawContext\_GetCanvas(drawContext));
            // 获取组件大小。
            auto size = OH\_ArkUI\_DrawContext\_GetSize(drawContext);
            // 绘制自定义内容。
            auto path = OH\_Drawing\_PathCreate();
            OH\_Drawing\_PathMoveTo(path, size.width / NUM\_5, size.height / NUM\_5);
            OH\_Drawing\_PathLineTo(path, size.width \* NUM\_4 / NUM\_5, size.height / NUM\_5);
            OH\_Drawing\_PathLineTo(path, size.width \* NUM\_4 / NUM\_5, size.height \* NUM\_4 / NUM\_5);
            OH\_Drawing\_PathLineTo(path, size.width / NUM\_5, size.height \* NUM\_4 / NUM\_5);
            OH\_Drawing\_PathLineTo(path, size.width / NUM\_5, size.height / NUM\_5);
            OH\_Drawing\_PathClose(path);
            auto brush = OH\_Drawing\_BrushCreate();
            OH\_Drawing\_BrushSetColor(brush, 0xFFF0FAFF); // 蓝白色
            OH\_Drawing\_CanvasAttachBrush(drawCanvas, brush);
            OH\_Drawing\_CanvasDrawPath(drawCanvas, path);
            // 释放资源
            OH\_Drawing\_BrushDestroy(brush);
            OH\_Drawing\_PathDestroy(path);
        }
    
        void OnDraw(ArkUI\_NodeCustomEvent \*event)
        {
            auto drawContext = OH\_ArkUI\_NodeCustomEvent\_GetDrawContextInDraw(event);
            // 获取图形绘制对象。
            auto drawCanvas = reinterpret\_cast<OH\_Drawing\_Canvas \*>(OH\_ArkUI\_DrawContext\_GetCanvas(drawContext));
            // 获取组件大小。
            auto size = OH\_ArkUI\_DrawContext\_GetSize(drawContext);
            // 绘制自定义内容。
            auto path = OH\_Drawing\_PathCreate();
            OH\_Drawing\_PathMoveTo(path, size.width / NUM\_4, size.height / NUM\_4);
            OH\_Drawing\_PathLineTo(path, size.width \* NUM\_3 / NUM\_4, size.height / NUM\_4);
            OH\_Drawing\_PathLineTo(path, size.width \* NUM\_3 / NUM\_4, size.height \* NUM\_3 / NUM\_4);
            OH\_Drawing\_PathLineTo(path, size.width / NUM\_4, size.height \* NUM\_3 / NUM\_4);
            OH\_Drawing\_PathLineTo(path, size.width / NUM\_4, size.height / NUM\_4);
            OH\_Drawing\_PathClose(path);
            auto brush = OH\_Drawing\_BrushCreate();
            OH\_Drawing\_BrushSetColor(brush, 0xff2787D9); // 浅蓝色
            OH\_Drawing\_CanvasAttachBrush(drawCanvas, brush);
            OH\_Drawing\_CanvasDrawPath(drawCanvas, path);
            // 释放资源
            OH\_Drawing\_BrushDestroy(brush);
            OH\_Drawing\_PathDestroy(path);
        }
    
        void OnDrawFront(ArkUI\_NodeCustomEvent \*event)
        {
            auto drawContext = OH\_ArkUI\_NodeCustomEvent\_GetDrawContextInDraw(event);
            // 获取图形绘制对象。
            auto drawCanvas = reinterpret\_cast<OH\_Drawing\_Canvas \*>(OH\_ArkUI\_DrawContext\_GetCanvas(drawContext));
            // 获取组件大小。
            auto size = OH\_ArkUI\_DrawContext\_GetSize(drawContext);
            // 绘制自定义内容。
            auto path = OH\_Drawing\_PathCreate();
            OH\_Drawing\_PathMoveTo(path, size.width / NUM\_3, size.height / NUM\_3);
            OH\_Drawing\_PathLineTo(path, size.width \* NUM\_2 / NUM\_3, size.height / NUM\_3);
            OH\_Drawing\_PathLineTo(path, size.width \* NUM\_2 / NUM\_3, size.height \* NUM\_2 / NUM\_3);
            OH\_Drawing\_PathLineTo(path, size.width / NUM\_3, size.height \* NUM\_2 / NUM\_3);
            OH\_Drawing\_PathLineTo(path, size.width / NUM\_3, size.height / NUM\_3);
            OH\_Drawing\_PathClose(path);
            auto brush = OH\_Drawing\_BrushCreate();
            OH\_Drawing\_BrushSetColor(brush, 0xFF004AAF); // 深蓝色
            OH\_Drawing\_CanvasAttachBrush(drawCanvas, brush);
            OH\_Drawing\_CanvasDrawPath(drawCanvas, path);
            // 释放资源
            OH\_Drawing\_BrushDestroy(brush);
            OH\_Drawing\_PathDestroy(path);
        }
        // ...
    };
    
    } // namespace NativeModule
    
    #endif // MYAPPLICATION\_ARKUICUSTOMNODE\_H
    
3.  使用自定义绘制组件和自定义容器创建示例界面。
    
    #include <arkui/native\_node\_napi.h>
    #include <arkui/native\_type.h>
    #include <js\_native\_api.h>
    
    #include "NativeEntry.h"
    #include "ArkUICustomContainerNode.h"
    #include "ArkUICustomNode.h"
    #include "ArkUIMessageMaskNode.h"
    
    // 全局环境变量声明
    static napi\_env g\_env = nullptr;
    // ...
    namespace NativeModule {
    // ...
    #define SIZE\_150 150
    // ...
    napi\_value CreateNativeRoot(napi\_env env, napi\_callback\_info info)
    {
        size\_t argc = 1;
        napi\_value args\[1\] = {nullptr};
    
        napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    
        // 获取NodeContent。
        ArkUI\_NodeContentHandle contentHandle;
        OH\_ArkUI\_GetNodeContentFromNapiValue(env, args\[0\], &contentHandle);
        NativeEntry::GetInstance()->SetContentHandle(contentHandle);
    
        // 创建自定义容器和自定义绘制组件。
        auto node = std::make\_shared<ArkUICustomContainerNode>();
        node->SetBackgroundColor(0xFFD5D5D5); // 浅灰色。
        auto customNode = std::make\_shared<ArkUICustomNode>();
        customNode->SetBackgroundColor(0xFF707070); // 深灰色。
        customNode->SetWidth(SIZE\_150);
        customNode->SetHeight(SIZE\_150);
        node->AddChild(customNode);
    
        // 保持Native侧对象到管理类中，维护生命周期。
        NativeEntry::GetInstance()->SetRootNode(node);
        g\_env = env;
        return nullptr;
    }
    
    napi\_value DestroyNativeRoot(napi\_env env, napi\_callback\_info info)
    {
        // 从管理类中释放Native侧对象。
        NativeEntry::GetInstance()->DisposeRootNode();
        return nullptr;
    }
    } // namespace NativeModule
    

#### 通过前景绘制实现消息蒙层

以下示例创建了一个消息提示组件，通过内容层绘制消息气泡与文本，并在前景层叠加星标装饰，实现消息高亮提示效果，常用于消息提醒和引导标记等场景。完整示例请参考[NativeNodeUtilsSample](https://gitcode.com/HarmonyOS_Samples/guide-snippets/tree/master/ArkUISample/NativeType/NativeNodeUtilsSample)。

未添加消息蒙层，未添加蒙层，没有前景层叠加星标装饰效果：

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/44/v3/qgPt_-PsQMe_s9FRrAY9Uw/zh-cn_image_0000002625107789.jpg?HW-CC-KV=V1&HW-CC-Date=20260612T073317Z&HW-CC-Expire=86400&HW-CC-Sign=FE229066BCF9BC68EA0E450E73FB2F048326176695370F0430E53B4693A87B3D)

添加消息蒙层，添加后有前景层叠加星标装饰效果：

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/c7/v3/WbMBiMXEQG6NRXtp5Jnu7A/zh-cn_image_0000002594668272.jpg?HW-CC-KV=V1&HW-CC-Date=20260612T073317Z&HW-CC-Expire=86400&HW-CC-Sign=F92BAFE8B1BD74B599BFEC4DD16AD58053219D9701C222E29402988D41F69464)

1.  按照[多层级绘制示例](#多层级绘制示例)章节准备前置工程。
    
2.  创建消息蒙层组件封装对象。
    
    #ifndef MYAPPLICATION\_ARKUIMESSAGEMASKNODE\_H
    #define MYAPPLICATION\_ARKUIMESSAGEMASKNODE\_H
    
    #include <cmath>
    #include <native\_drawing/drawing\_brush.h>
    #include <native\_drawing/drawing\_canvas.h>
    #include <native\_drawing/drawing\_color\_filter.h>
    #include <native\_drawing/drawing\_font.h>
    #include <native\_drawing/drawing\_font\_collection.h>
    #include <native\_drawing/drawing\_path.h>
    #include <native\_drawing/drawing\_pen.h>
    #include <native\_drawing/drawing\_point.h>
    #include <native\_drawing/drawing\_rect.h>
    #include <native\_drawing/drawing\_round\_rect.h>
    #include <native\_drawing/drawing\_text\_typography.h>
    
    #include <string>
    
    #include "ArkUINode.h"
    
    namespace NativeModule {
    class ArkUIMessageMaskNode : public ArkUINode {
    public:
        // 使用自定义组件类型ARKUI\_NODE\_CUSTOM创建组件
        ArkUIMessageMaskNode()
            : ArkUINode(
                  (NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI\_NODE\_CUSTOM))
        {
            // 注册自定义事件监听器
            nativeModule\_->addNodeCustomEventReceiver(handle\_, OnStaticCustomEvent);
            // 声明自定义事件并转递自身作为自定义数据
            nativeModule\_->registerNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_FRONT, 0, this);
            nativeModule\_->registerNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW, 0, this);
            nativeModule\_->registerNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_BEHIND, 0, this);
        }
    
        ~ArkUIMessageMaskNode() override
        {
            // 反注册自定义事件监听器
            nativeModule\_->removeNodeCustomEventReceiver(handle\_, OnStaticCustomEvent);
            // 取消声明自定义事件
            nativeModule\_->unregisterNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_FRONT);
            nativeModule\_->unregisterNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW);
            nativeModule\_->unregisterNodeCustomEvent(handle\_, ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_BEHIND);
        }
    
        // 设置消息文本
        void SetMessage(const std::string& message)
        {
            message\_ = message;
            nativeModule\_->markDirty(handle\_, NODE\_NEED\_RENDER);
        }
    
        // 设置是否显示蒙层
        void SetMaskVisible(bool visible)
        {
            maskVisible\_ = visible;
            nativeModule\_->markDirty(handle\_, NODE\_NEED\_RENDER);
        }
    
    private:
        static constexpr int starDecorationCount = 3;
        static constexpr int starPointCount = 5;
        static constexpr float starStartAngleDegrees = -90.0f;
        static constexpr float starAngleStepDegrees = 72.0f;
        static constexpr float starInnerAngleOffsetDegrees = 36.0f;
        static constexpr float starInnerRadiusRatio = 0.4f;
        static constexpr float degreeToRadian = 3.14159265f / 180.0f;
        static constexpr float messageTextFontSize = 23.0f;
    
        static void OnStaticCustomEvent(ArkUI\_NodeCustomEvent\* event)
        {
            auto customNode = reinterpret\_cast<ArkUIMessageMaskNode\*>(OH\_ArkUI\_NodeCustomEvent\_GetUserData(event));
            auto type = OH\_ArkUI\_NodeCustomEvent\_GetEventType(event);
            switch (type) {
                case ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_BEHIND:
                    customNode->OnDrawBehind(event);
                    break;
                case ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW:
                    customNode->OnDraw(event);
                    break;
                case ARKUI\_NODE\_CUSTOM\_EVENT\_ON\_DRAW\_FRONT:
                    customNode->OnDrawFront(event);
                    break;
                default:
                    break;
            }
        }
    
        // 自定义内容背景层：绘制聊天界面背景
        void OnDrawBehind(ArkUI\_NodeCustomEvent\* event)
        {
            auto drawContext = OH\_ArkUI\_NodeCustomEvent\_GetDrawContextInDraw(event);
            auto canvas = reinterpret\_cast<OH\_Drawing\_Canvas\*>(OH\_ArkUI\_DrawContext\_GetCanvas(drawContext));
            auto size = OH\_ArkUI\_DrawContext\_GetSize(drawContext);
    
            // 绘制浅灰色背景
            auto bgRect = OH\_Drawing\_RectCreate(0, 0, size.width, size.height);
            auto brush = OH\_Drawing\_BrushCreate();
            OH\_Drawing\_BrushSetColor(brush, 0xFFF5F5F5);
            OH\_Drawing\_CanvasAttachBrush(canvas, brush);
            OH\_Drawing\_CanvasDrawRect(canvas, bgRect);
            OH\_Drawing\_CanvasDetachBrush(canvas);
            OH\_Drawing\_BrushDestroy(brush);
            OH\_Drawing\_RectDestroy(bgRect);
        }
    
        // 自定义内容层
        void OnDraw(ArkUI\_NodeCustomEvent\* event)
        {
            auto drawContext = OH\_ArkUI\_NodeCustomEvent\_GetDrawContextInDraw(event);
            auto canvas = reinterpret\_cast<OH\_Drawing\_Canvas\*>(OH\_ArkUI\_DrawContext\_GetCanvas(drawContext));
            auto size = OH\_ArkUI\_DrawContext\_GetSize(drawContext);
    
            float padding = 50.0f;
            float bubbleWidth = size.width - 2 \* padding;
            float bubbleHeight = size.height - 2 \* padding;
            float cornerRadius = 8.0f;
            float textX = padding + 15.0f;
            float textY = padding + 20.0f;
            float textMaxWidth = bubbleWidth - 30.0f;
    
            // 绘制气泡阴影
            auto shadowRect = OH\_Drawing\_RectCreate(
                padding + 2, padding + 2, padding + bubbleWidth + 2, padding + bubbleHeight + 2);
            auto\* shadowRoundRect = OH\_Drawing\_RoundRectCreate(shadowRect, cornerRadius, cornerRadius);
            auto shadowBrush = OH\_Drawing\_BrushCreate();
            OH\_Drawing\_BrushSetColor(shadowBrush, 0x30000000);
            OH\_Drawing\_CanvasAttachBrush(canvas, shadowBrush);
            OH\_Drawing\_CanvasDrawRoundRect(canvas, shadowRoundRect);
            OH\_Drawing\_CanvasDetachBrush(canvas);
            OH\_Drawing\_BrushDestroy(shadowBrush);
            OH\_Drawing\_RoundRectDestroy(shadowRoundRect);
            OH\_Drawing\_RectDestroy(shadowRect);
    
            // 绘制绿色气泡背景
            auto bubbleRect = OH\_Drawing\_RectCreate(padding, padding, padding + bubbleWidth, padding + bubbleHeight);
            auto\* bubbleRoundRect = OH\_Drawing\_RoundRectCreate(bubbleRect, cornerRadius, cornerRadius);
            auto bubbleBrush = OH\_Drawing\_BrushCreate();
            OH\_Drawing\_BrushSetColor(bubbleBrush, 0xFF95EC69);
            OH\_Drawing\_CanvasAttachBrush(canvas, bubbleBrush);
            OH\_Drawing\_CanvasDrawRoundRect(canvas, bubbleRoundRect);
            OH\_Drawing\_CanvasDetachBrush(canvas);
            OH\_Drawing\_BrushDestroy(bubbleBrush);
    
            // 绘制气泡边框
            auto pen = OH\_Drawing\_PenCreate();
            OH\_Drawing\_PenSetWidth(pen, 1.0f);
            OH\_Drawing\_PenSetColor(pen, 0xFF7FD65A);
            OH\_Drawing\_CanvasAttachPen(canvas, pen);
            OH\_Drawing\_CanvasDrawRoundRect(canvas, bubbleRoundRect);
            OH\_Drawing\_CanvasDetachPen(canvas);
            OH\_Drawing\_PenDestroy(pen);
            OH\_Drawing\_RoundRectDestroy(bubbleRoundRect);
            OH\_Drawing\_RectDestroy(bubbleRect);
    
            // 绘制消息文本
            DrawMessageText(canvas, textX, textY, textMaxWidth);
        }
    
        // 自定义内容前景层：绘制装饰性蒙层
        void OnDrawFront(ArkUI\_NodeCustomEvent\* event)
        {
            if (!maskVisible\_) {
                return;
            }
    
            auto drawContext = OH\_ArkUI\_NodeCustomEvent\_GetDrawContextInDraw(event);
            auto canvas = reinterpret\_cast<OH\_Drawing\_Canvas\*>(OH\_ArkUI\_DrawContext\_GetCanvas(drawContext));
    
            float padding = 50.0f;
    
            auto starBrush = OH\_Drawing\_BrushCreate();
            OH\_Drawing\_BrushSetColor(starBrush, 0x88FFFFFF);
            OH\_Drawing\_CanvasAttachBrush(canvas, starBrush);
    
            const float starRadius = 13.0f;
            const float textLeftX = padding + 26.0f;
            const float textRightX = padding + 146.0f;
            const float starBottomY = padding + 50.0f;
            const float starTopY = padding + 10.0f;
            for (int i = 0; i < starDecorationCount; ++i) {
                float t = static\_cast<float>(i) / static\_cast<float>(starDecorationCount - 1);
                float starX = textLeftX + (textRightX - textLeftX) \* t;
                float starY = starBottomY + (starTopY - starBottomY) \* t;
                DrawStar(canvas, starX, starY, starRadius);
            }
    
            OH\_Drawing\_CanvasDetachBrush(canvas);
            OH\_Drawing\_BrushDestroy(starBrush);
        }
    
        // 绘制五角星
        void DrawStar(OH\_Drawing\_Canvas\* canvas, float cx, float cy, float radius)
        {
            auto path = OH\_Drawing\_PathCreate();
            for (int i = 0; i < starPointCount; ++i) {
                float angle = starStartAngleDegrees + i \* starAngleStepDegrees;
                float rad = angle \* degreeToRadian;
                float x = cx + radius \* std::cos(rad);
                float y = cy + radius \* std::sin(rad);
                if (i == 0) {
                    OH\_Drawing\_PathMoveTo(path, x, y);
                } else {
                    OH\_Drawing\_PathLineTo(path, x, y);
                }
    
                // 内角点
                float innerAngle = angle + starInnerAngleOffsetDegrees;
                float innerRad = innerAngle \* degreeToRadian;
                float innerX = cx + radius \* starInnerRadiusRatio \* std::cos(innerRad);
                float innerY = cy + radius \* starInnerRadiusRatio \* std::sin(innerRad);
                OH\_Drawing\_PathLineTo(path, innerX, innerY);
            }
    
            OH\_Drawing\_PathClose(path);
            OH\_Drawing\_CanvasDrawPath(canvas, path);
            OH\_Drawing\_PathDestroy(path);
        }
    
        // 绘制消息文本
        void DrawMessageText(OH\_Drawing\_Canvas\* canvas, float x, float y, float maxWidth)
        {
            // 创建字体集合
            auto\* fontCollection = OH\_Drawing\_CreateFontCollection();
    
            // 创建排版样式
            auto\* typographyStyle = OH\_Drawing\_CreateTypographyStyle();
            OH\_Drawing\_SetTypographyTextAlign(typographyStyle, TEXT\_ALIGN\_LEFT);
    
            // 创建排版处理器
            auto\* typographyHandler = OH\_Drawing\_CreateTypographyHandler(typographyStyle, fontCollection);
    
            // 创建文本样式
            auto\* textStyle = OH\_Drawing\_CreateTextStyle();
            OH\_Drawing\_SetTextStyleColor(textStyle, 0xFF000000); // 纯黑
            OH\_Drawing\_SetTextStyleFontSize(textStyle, messageTextFontSize);
            OH\_Drawing\_SetTextStyleFontWeight(textStyle, FONT\_WEIGHT\_400);
            auto textBrush = OH\_Drawing\_BrushCreate();
            OH\_Drawing\_BrushSetColor(textBrush, 0xFF000000);
            OH\_Drawing\_SetTextStyleForegroundBrush(textStyle, textBrush);
    
            // 添加文本
            OH\_Drawing\_TypographyHandlerPushTextStyle(typographyHandler, textStyle);
            OH\_Drawing\_TypographyHandlerAddText(typographyHandler, message\_.c\_str());
            OH\_Drawing\_TypographyHandlerPopTextStyle(typographyHandler);
    
            // 创建排版对象并绘制
            auto\* typography = OH\_Drawing\_CreateTypography(typographyHandler);
            OH\_Drawing\_TypographyLayout(typography, maxWidth);
            OH\_Drawing\_TypographyPaint(typography, canvas, x, y);
    
            // 释放资源
            OH\_Drawing\_DestroyTextStyle(textStyle);
            OH\_Drawing\_DestroyTypography(typography);
            OH\_Drawing\_DestroyTypographyHandler(typographyHandler);
            OH\_Drawing\_DestroyTypographyStyle(typographyStyle);
            OH\_Drawing\_DestroyFontCollection(fontCollection);
            OH\_Drawing\_BrushDestroy(textBrush);
        }
    
        std::string message\_ = "";
        bool maskVisible\_ = false;
    };
    } // namespace NativeModule
    
    #endif // MYAPPLICATION\_ARKUIMESSAGEMASKNODE\_H
    
3.  使用消息蒙层组件创建示例界面。
    
    #include <arkui/native\_node\_napi.h>
    #include <arkui/native\_type.h>
    #include <js\_native\_api.h>
    
    #include "NativeEntry.h"
    #include "ArkUICustomContainerNode.h"
    #include "ArkUICustomNode.h"
    #include "ArkUIMessageMaskNode.h"
    
    // 全局环境变量声明
    static napi\_env g\_env = nullptr;
    // ...
    namespace NativeModule {
    // ...
    napi\_value CreateNativeMessageRoot(napi\_env env, napi\_callback\_info info)
    {
        constexpr int32\_t messageMaskWidth = 400;
        constexpr int32\_t messageMaskHeight = 200;
    
        size\_t argc = 1;
        napi\_value args\[1\] = {nullptr};
    
        napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    
        // 避免重复创建导致的重复挂载
        NativeEntry::GetInstance()->DisposeRootNode();
    
        // 获取NodeContent
        ArkUI\_NodeContentHandle contentHandle;
        OH\_ArkUI\_GetNodeContentFromNapiValue(env, args\[0\], &contentHandle);
        NativeEntry::GetInstance()->SetContentHandle(contentHandle);
    
        auto nodeAPI = NativeModuleInstance::GetInstance()->GetNativeNodeAPI();
        auto rootColumn = std::make\_shared<ArkUIColumnNode>();
        auto rootColumnHandle = rootColumn->GetHandle();
        
        // 设置根容器样式
        ArkUI\_NumberValue paddingValue\[\] = {{.f32 = 20.0f}};
        ArkUI\_AttributeItem paddingItem = {paddingValue, 1};
        nodeAPI->setAttribute(rootColumnHandle, NODE\_PADDING, &paddingItem);
    
        ArkUI\_NumberValue bgColorValue\[\] = {{.u32 = 0xFFFFFFFF}};
        ArkUI\_AttributeItem bgColorItem = {bgColorValue, 1};
        nodeAPI->setAttribute(rootColumnHandle, NODE\_BACKGROUND\_COLOR, &bgColorItem);
        
        // 创建消息气泡组件
        auto maskNode = std::make\_shared<ArkUIMessageMaskNode>();
        maskNode->SetWidth(messageMaskWidth);
        maskNode->SetHeight(messageMaskHeight);
        maskNode->SetMessage("您有一条新消息");
        maskNode->SetMaskVisible(false);  // 初始不显示蒙层
        
        // 创建按钮用于切换蒙层效果
        auto buttonNode = std::make\_shared<ArkUINode>(nodeAPI->createNode(ARKUI\_NODE\_BUTTON));
        auto buttonHandle = buttonNode->GetHandle();
        
        // 设置按钮文本
        ArkUI\_AttributeItem labelItem;
        const char\* buttonLabel = "切换蒙层效果";
        labelItem.string = buttonLabel;
        nodeAPI->setAttribute(buttonHandle, NODE\_BUTTON\_LABEL, &labelItem);
        
        // 设置按钮样式
        ArkUI\_NumberValue marginValue\[\] = {{.f32 = 20.0f}};
        ArkUI\_AttributeItem marginItem = {marginValue, 1};
        nodeAPI->setAttribute(buttonHandle, NODE\_MARGIN, &marginItem);
        
        ArkUI\_NumberValue btnBgColorValue\[\] = {{.u32 = 0xFF2787D9}};
        ArkUI\_AttributeItem btnBgColorItem = {btnBgColorValue, 1};
        nodeAPI->setAttribute(buttonHandle, NODE\_BACKGROUND\_COLOR, &btnBgColorItem);
    
        // 设置按钮点击事件
        auto onClick = \[\](ArkUI\_NodeEvent \*event) {
            auto maskNode = (ArkUIMessageMaskNode \*)OH\_ArkUI\_NodeEvent\_GetUserData(event);
            static bool highlighted = false;
            highlighted = !highlighted;
            maskNode->SetMaskVisible(highlighted);
        };
        buttonNode->RegisterOnClick(onClick, maskNode.get());
        
        // 将组件添加到根容器
        rootColumn->AddChild(buttonNode);
        rootColumn->AddChild(maskNode);
    
        // 保持Native侧对象到管理类中，维护生命周期
        NativeEntry::GetInstance()->SetRootNode(rootColumn);
        return nullptr;
    }
    
    napi\_value DestroyNativeRoot(napi\_env env, napi\_callback\_info info)
    {
        // 从管理类中释放Native侧对象。
        NativeEntry::GetInstance()->DisposeRootNode();
        return nullptr;
    }
    } // namespace NativeModule