绑定拖拽事件
======

ArkUI开发框架针对拖拽事件提供了[NODE\_ON\_PRE\_DRAG](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeeventtype)，[NODE\_ON\_DRAG\_START](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeeventtype)，[NODE\_ON\_DROP](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeeventtype)，[NODE\_ON\_DRAG\_ENTER](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeeventtype)，[NODE\_ON\_DRAG\_MOVE](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeeventtype)，[NODE\_ON\_DRAG\_LEAVE](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeeventtype)，[NODE\_ON\_DRAG\_END](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeeventtype)等组件事件，当拖拽在不同的阶段时会触发对应的组件事件，完成对应的数据处理操作，实现期望的拖拽交互能力。

#### 通用拖拽

ArkUI提供了使用C和C++开发拖拽功能的能力，开发者可调用C API实现拖拽功能。以下以Image组件为例，详细介绍C API实现拖拽功能的基本步骤，以及在开发过程中需要注意的事项。完整示例请参考[NativeDragDrop](https://gitcode.com/HarmonyOS_Samples/guide-snippets/tree/master/ArkUISample/NativeDragDrop)。

1.  组件拖拽设置。
    
    通过[OH\_ArkUI\_GetModuleInterface](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-interface-h#oh_arkui_getmoduleinterface)接口初始化nodeAPI，创建节点等操作均需通过nodeAPI完成。
    
    ArkUI\_NativeNodeAPI\_1 \*nativeNodeAPI = nullptr;
    OH\_ArkUI\_GetModuleInterface(ARKUI\_NATIVE\_NODE, ArkUI\_NativeNodeAPI\_1, nativeNodeAPI);
    nodeAPI = nativeNodeAPI;
    
    创建Image节点，通过[OH\_ArkUI\_SetNodeDraggable](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-drag-and-drop-h#oh_arkui_setnodedraggable)设置节点可拖拽，并设置其他相关属性。
    
    dragImage2 = nodeAPI->createNode(ARKUI\_NODE\_IMAGE);
    SetId(dragImage2, "dragImage");
    SetCommonAttribute(dragImage2, 140.0f, 140.0f, 0xFFFFFFFF, 5.0f);
    // 图片src/main/resources/base/media/seagull.png需要替换为开发者所需的资源文件
    SetImageSrc(dragImage2, "/resources/base/media/seagull.png");
    OH\_ArkUI\_SetNodeDraggable(dragImage2, true);
    nodeAPI->registerNodeEvent(dragImage2, NODE\_ON\_DRAG\_START, 1, nullptr);
    
    #define DEFAULT\_WIDTH 200.0
    // 设置节点宽度
    void SetWidth(ArkUI\_NodeHandle &node, float width = DEFAULT\_WIDTH)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue widthValue\[\] = {width};
        ArkUI\_AttributeItem widthItem = {widthValue, 1};
        nodeAPI->setAttribute(node, NODE\_WIDTH, &widthItem);
    }
    
    #define DEFAULT\_HEIGHT 200.0
    // 设置节点高度
    void SetHeight(ArkUI\_NodeHandle &node, float height = DEFAULT\_HEIGHT)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue heightValue\[\] = {height};
        ArkUI\_AttributeItem heightItem = {heightValue, 1};
        nodeAPI->setAttribute(node, NODE\_HEIGHT, &heightItem);
    }
    
    #define DEFAULT\_BG\_COLOR 0xFFFFFFFF
    // 设置节点背景颜色
    void SetBackgroundColor(ArkUI\_NodeHandle &node, uint32\_t color = DEFAULT\_BG\_COLOR)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue colorValue\[\] = {{.u32 = color}};
        ArkUI\_AttributeItem colorItem = {colorValue, 1};
        nodeAPI->setAttribute(node, NODE\_BACKGROUND\_COLOR, &colorItem);
    }
    
    #define DEFAULT\_MARGIN 5.0
    // 设置节点外边距
    void SetMargin(ArkUI\_NodeHandle &node, float margin = DEFAULT\_MARGIN)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue marginValue\[\] = {margin};
        ArkUI\_AttributeItem marginItem = {marginValue, 1};
        nodeAPI->setAttribute(node, NODE\_MARGIN, &marginItem);
    }
    
    // 设置Button节点标签
    void SetButtonLabel(ArkUI\_NodeHandle &node, const char \*label)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_AttributeItem NODE\_Button\_SRC\_Item = {.string = label};
        nodeAPI->setAttribute(node, NODE\_BUTTON\_LABEL, &NODE\_Button\_SRC\_Item);
    }
    
    // 设置节点标识符
    void SetId(ArkUI\_NodeHandle &node, const char \*id)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_AttributeItem idItem = {.string = id};
        nodeAPI->setAttribute(node, NODE\_ID, &idItem);
    }
    
    #define DEFAULT\_BORDER\_WIDTH 0.0
    // 设置节点边框宽度
    void SetBorderWidth(ArkUI\_NodeHandle &node, float width = DEFAULT\_BORDER\_WIDTH)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue borderWidthValue\[\] = {width};
        ArkUI\_AttributeItem borderWidthItem = {borderWidthValue, 1};
        nodeAPI->setAttribute(node, NODE\_BORDER\_WIDTH, &borderWidthItem);
    }
    
    #define DEFAULT\_BORDER\_COLOR 0xFF000000
    // 设置节点边框颜色
    void SetBorderColor(ArkUI\_NodeHandle &node, uint32\_t color = DEFAULT\_BORDER\_COLOR)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue borderColorValue\[\] = {{.u32 = color}};
        ArkUI\_AttributeItem borderColorItem = {borderColorValue, 1};
        nodeAPI->setAttribute(node, NODE\_BORDER\_COLOR, &borderColorItem);
    }
    
    // 设置节点常用属性（宽高、背景色、外边距、边框样式）
    void SetCommonAttribute(ArkUI\_NodeHandle &node, float width = DEFAULT\_WIDTH, float height = DEFAULT\_HEIGHT,
                            unsigned int color = DEFAULT\_BG\_COLOR, float margin = DEFAULT\_MARGIN)
    {
        SetWidth(node, width);
        SetHeight(node, height);
        SetBackgroundColor(node, color);
        SetMargin(node, margin);
        SetBorderWidth(node, DEFAULT\_BORDER\_WIDTH);
        SetBorderColor(node);
    }
    
    void SetImageSrc(ArkUI\_NodeHandle &node, const char \*src)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_AttributeItem imageSrcItem = {.string = src};
        nodeAPI->setAttribute(node, NODE\_IMAGE\_SRC, &imageSrcItem);
    }
    
2.  自定义拖拽预览和背板图。
    
    创建[pixelMap](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-pixelmap-native-h#oh_pixelmapnative_createpixelmap)，设置pixelMap的宽高等各项属性。设置Image节点的[ArkUI\_DragPreviewOption](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-arkui-nativemodule-arkui-dragpreviewoption)，可用于设置跟手图的圆角、角标等。
    
    // 创建pixelMap
    uint8\_t data\[960000\];
    size\_t dataSize = 960000;
    for (int i = 0; i < dataSize; i++) {
        data\[i\] = i + 1;
    }
    // 创建参数结构体实例，并设置参数
    OH\_Pixelmap\_InitializationOptions \*createOpts;
    OH\_PixelmapInitializationOptions\_Create(&createOpts);
    OH\_PixelmapInitializationOptions\_SetWidth(createOpts, 200U);
    OH\_PixelmapInitializationOptions\_SetHeight(createOpts, 200U);
    OH\_PixelmapInitializationOptions\_SetPixelFormat(createOpts, PIXEL\_FORMAT\_BGRA\_8888);
    OH\_PixelmapInitializationOptions\_SetAlphaType(createOpts, PIXELMAP\_ALPHA\_TYPE\_UNKNOWN);
    // 设置自定义跟手图
    OH\_PixelmapNative \*pixelmap = nullptr;
    OH\_PixelmapNative\_CreatePixelmap(data, dataSize, createOpts, &pixelmap);
    OH\_PixelmapNative\_Opacity(pixelmap, 0.1f);
    OH\_ArkUI\_SetNodeDragPreview(node, pixelmap);
    // 设置跟手图选项
    auto \*previewOptionsText = OH\_ArkUI\_CreateDragPreviewOption();
    OH\_ArkUI\_DragPreviewOption\_SetScaleMode(previewOptionsText, ARKUI\_DRAG\_PREVIEW\_SCALE\_DISABLED);
    OH\_ArkUI\_DragPreviewOption\_SetNumberBadgeEnabled(previewOptionsText, true);
    OH\_ArkUI\_DragPreviewOption\_SetBadgeNumber(previewOptionsText, 10U);
    OH\_ArkUI\_DragPreviewOption\_SetDefaultShadowEnabled(previewOptionsText, true);
    OH\_ArkUI\_DragPreviewOption\_SetDefaultRadiusEnabled(previewOptionsText, true);
    int returnValue = OH\_ArkUI\_DragPreviewOption\_SetDefaultAnimationBeforeLiftingEnabled(previewOptionsText, true);
    OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "Manager",
        "dragTest DragPreviewOption\_SetDefaultAnimationBeforeLiftingEnabled returnValue = %{public}d",
        returnValue);
    OH\_ArkUI\_SetNodeDragPreviewOption(node, previewOptionsText);
    
3.  设置相关事件。
    
    C API的事件通过统一的回调来接收，当收到事件时通过[eventType](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeeventtype)进行区分。
    
    nodeAPI->addNodeEventReceiver(dragNode, \[\](ArkUI\_NodeEvent \*event) {
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "RegisterNodeEventFirstReceiver called");
        auto eventType = OH\_ArkUI\_NodeEvent\_GetEventType(event);
        auto preDragStatus = OH\_ArkUI\_NodeEvent\_GetPreDragStatus(event);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "eventType = %{public}d, preDragStatus = %{public}d", eventType, preDragStatus);
        auto \*dragEvent = OH\_ArkUI\_NodeEvent\_GetDragEvent(event);
        switch (eventType) {
            case NODE\_ON\_PRE\_DRAG:
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_PRE\_DRAG Event Receive");
                break;
            case NODE\_ON\_CLICK:
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_CLICK Event Receive");
                break;
            case NODE\_ON\_DROP:
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_DROP Event Receive");
                break;
            case NODE\_ON\_DRAG\_ENTER:
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_DRAG\_ENTER Event Receive");
                break;
            case NODE\_ON\_DRAG\_MOVE:
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_DRAG\_MOVE Event Receive");
                break;
            case NODE\_ON\_DRAG\_LEAVE:
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_DRAG\_LEAVE Event Receive");
                break;
            case NODE\_ON\_DRAG\_START: {
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_DRAG\_START Event Receive");
                // ...
                break;
            }
            case NODE\_ON\_DRAG\_END: {
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_DRAG\_END Event Receive");
                // ...
                break;
            }
            default:
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "UNKNOWN Event Receive");
                break;
        }
    });
    
4.  处理NODE\_ON\_DRAG\_START事件。
    
    在NODE\_ON\_DRAG\_START事件中，应用可以执行起拖阶段所需的操作，通常涉及处理起拖过程的数据。例如，创建[OH\_UdmfRecord](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-udmf-oh-udmfrecord)，将用于拖拽图片所需的数据imageValue以[OH\_UdsFileUri](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-udmf-oh-udsfileuri)类型添加到OH\_UdmfRecord中，接着将OH\_UdmfRecord设置到[OH\_UdmfData](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-udmf-oh-udmfdata)中，最后将OH\_UdmfData设置到[DragEvent](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-arkui-nativemodule-arkui-dragevent)中。
    
    void SetImageData(ArkUI\_DragEvent\* dragEvent)
    {
        int returnValue;
        OH\_UdmfRecord \*record = OH\_UdmfRecord\_Create();
        OH\_UdsFileUri \*imageValue = OH\_UdsFileUri\_Create();
        // 图片src/main/resources/base/media/seagull.png需要替换为开发者所需的资源文件
        returnValue = OH\_UdsFileUri\_SetFileUri(imageValue, "/resources/base/media/seagull.png");
        returnValue = OH\_UdmfRecord\_AddFileUri(record, imageValue);
        OH\_UdmfData \*data = OH\_UdmfData\_Create();
        returnValue = OH\_UdmfData\_AddRecord(data, record);
        returnValue = OH\_ArkUI\_DragEvent\_SetData(dragEvent, data);
    }
    // ...
                case NODE\_ON\_DRAG\_START: {
                    OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_DRAG\_START EventReceiver");
                    SetImageData(dragEvent);
                    break;
                }
    
5.  处理NODE\_ON\_DROP事件。
    
    在NODE\_ON\_DROP事件中，应用可以执行与落入阶段相关的操作，通常需要获取拖拽过程中传递的数据。例如，引用[udmf\_meta.h](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-udmf-meta-h)头文件，获取[OH\_UdmfData](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-udmf-oh-udmfdata)，判断是否存在所需的数据类型，从[OH\_UdmfRecord](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-udmf-oh-udmfrecord)中提取相应的数据，最后销毁指针。
    
    void GetDragData(ArkUI\_DragEvent\* dragEvent)
    {
        // 获取UDMF data
        int returnValue;
        // 创建OH\_UdmfData对象
        OH\_UdmfData \*data = OH\_UdmfData\_Create();
        returnValue = OH\_ArkUI\_DragEvent\_GetUdmfData(dragEvent, data);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "OH\_ArkUI\_DragEvent\_GetUdmfData returnValue = %{public}d", returnValue);
        // 判断OH\_UdmfData是否有对应的类型
        bool resultUdmf = OH\_UdmfData\_HasType(data, UDMF\_META\_GENERAL\_FILE);
        if (resultUdmf) {
            // 获取OH\_UdmfData的记录
            unsigned int recordsCount = 0;
            OH\_UdmfRecord \*\*records = OH\_UdmfData\_GetRecords(data, &recordsCount);
            // 获取records中的元素
            int returnStatus;
            for (int i = 0; i < recordsCount; i++) {
                // 从OH\_UdmfRecord中获取文件类型数据
                OH\_UdsFileUri \*imageValue = OH\_UdsFileUri\_Create();
                returnStatus = OH\_UdmfRecord\_GetFileUri(records\[i\], imageValue);
                const char \*fileUri = OH\_UdsFileUri\_GetFileUri(imageValue);
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
                    "dragTest OH\_UdmfRecord\_GetPlainText "
                    "returnStatus= %{public}d "
                    "fileUri= %{public}s",
                    returnStatus, fileUri);
                // 使用结束后销毁指针
                OH\_UdsFileUri\_Destroy(imageValue);
            }
            if (recordsCount != 0) {
                OH\_ArkUI\_DragEvent\_SetDragResult(dragEvent, ARKUI\_DRAG\_RESULT\_SUCCESSFUL);
                ArkUI\_DropOperation option;
                OH\_ArkUI\_DragEvent\_GetDropOperation(dragEvent, &option);
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
                    "OH\_ArkUI\_DragEvent\_GetDropOperation returnValue = %{public}d", option);
            }
        } else {
            OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
                "OH\_UdmfData\_HasType not contain UDMF\_META\_GENERAL\_FILE");
        }
        int32\_t count;
        OH\_ArkUI\_DragEvent\_GetDataTypeCount(dragEvent, &count);
        if (count <= 0 || count >= 128U) {
            return;
        }
        char \*\*eventTypeArray = new char \*\[count\];
        for (int i = 0; i < count; i++) {
            eventTypeArray\[i\] = new char\[128U\];
        }
        OH\_ArkUI\_DragEvent\_GetDataTypes(dragEvent, eventTypeArray, count, 128U);
        for (int i = 0; i < count; i++) {
            OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
                "OH\_ArkUI\_DragEvent\_GetDataTypes returnValue = %{public}s", eventTypeArray\[i\]);
        }
    }
    // ...
                case NODE\_ON\_DROP: {
                    OH\_ArkUI\_DragEvent\_SetSuggestedDropOperation(dragEvent, ARKUI\_DROP\_OPERATION\_COPY);
                    OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_DROP EventReceiver");
                    GetDragData(dragEvent);
                    break;
                }
    

#### DragAction主动发起拖拽

除了通用拖拽以外，ArkUI还提供了使用C API实现主动发起拖拽的能力。以下以文本拖拽为例，详细介绍C-API实现主动发起拖拽的基本步骤，以及在开发过程中需要注意的事项。完整示例请参考[NativeDragDrop](https://gitcode.com/HarmonyOS_Samples/guide-snippets/tree/master/ArkUISample/NativeDragDrop)。

1.  节点注册事件。
    
    创建Button节点，设置按钮相关属性，同时需要注册[NODE\_ON\_TOUCH\_INTERCEPT](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeeventtype)事件。
    
    // buttonTouch作为targetId，用于区分不同target的事件。
    enum {
        BUTTON\_TOUCH = 1
    };
    
    dragButton = nodeAPI->createNode(ARKUI\_NODE\_BUTTON);
    SetId(dragButton, "dragBt3");
    SetCommonAttribute(dragButton, 80.0f, 50.0f, 0xFFFF0000, 20.0f);
    SetButtonLabel(dragButton, "拖起");
    nodeAPI->registerNodeEvent(dragButton, NODE\_ON\_TOUCH\_INTERCEPT, BUTTON\_TOUCH, nullptr);
    
    #define DEFAULT\_WIDTH 200.0
    // 设置节点宽度
    void SetWidth(ArkUI\_NodeHandle &node, float width = DEFAULT\_WIDTH)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue widthValue\[\] = {width};
        ArkUI\_AttributeItem widthItem = {widthValue, 1};
        nodeAPI->setAttribute(node, NODE\_WIDTH, &widthItem);
    }
    
    #define DEFAULT\_HEIGHT 200.0
    // 设置节点高度
    void SetHeight(ArkUI\_NodeHandle &node, float height = DEFAULT\_HEIGHT)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue heightValue\[\] = {height};
        ArkUI\_AttributeItem heightItem = {heightValue, 1};
        nodeAPI->setAttribute(node, NODE\_HEIGHT, &heightItem);
    }
    
    #define DEFAULT\_BG\_COLOR 0xFFFFFFFF
    // 设置节点背景颜色
    void SetBackgroundColor(ArkUI\_NodeHandle &node, uint32\_t color = DEFAULT\_BG\_COLOR)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue colorValue\[\] = {{.u32 = color}};
        ArkUI\_AttributeItem colorItem = {colorValue, 1};
        nodeAPI->setAttribute(node, NODE\_BACKGROUND\_COLOR, &colorItem);
    }
    
    #define DEFAULT\_MARGIN 5.0
    // 设置节点外边距
    void SetMargin(ArkUI\_NodeHandle &node, float margin = DEFAULT\_MARGIN)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue marginValue\[\] = {margin};
        ArkUI\_AttributeItem marginItem = {marginValue, 1};
        nodeAPI->setAttribute(node, NODE\_MARGIN, &marginItem);
    }
    
    // 设置Button节点标签
    void SetButtonLabel(ArkUI\_NodeHandle &node, const char \*label)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_AttributeItem NODE\_Button\_SRC\_Item = {.string = label};
        nodeAPI->setAttribute(node, NODE\_BUTTON\_LABEL, &NODE\_Button\_SRC\_Item);
    }
    
    // 设置节点标识符
    void SetId(ArkUI\_NodeHandle &node, const char \*id)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_AttributeItem idItem = {.string = id};
        nodeAPI->setAttribute(node, NODE\_ID, &idItem);
    }
    
    #define DEFAULT\_BORDER\_WIDTH 0.0
    // 设置节点边框宽度
    void SetBorderWidth(ArkUI\_NodeHandle &node, float width = DEFAULT\_BORDER\_WIDTH)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue borderWidthValue\[\] = {width};
        ArkUI\_AttributeItem borderWidthItem = {borderWidthValue, 1};
        nodeAPI->setAttribute(node, NODE\_BORDER\_WIDTH, &borderWidthItem);
    }
    
    #define DEFAULT\_BORDER\_COLOR 0xFF000000
    // 设置节点边框颜色
    void SetBorderColor(ArkUI\_NodeHandle &node, uint32\_t color = DEFAULT\_BORDER\_COLOR)
    {
        if (!nodeAPI) {
            return;
        }
        ArkUI\_NumberValue borderColorValue\[\] = {{.u32 = color}};
        ArkUI\_AttributeItem borderColorItem = {borderColorValue, 1};
        nodeAPI->setAttribute(node, NODE\_BORDER\_COLOR, &borderColorItem);
    }
    
    // 设置节点常用属性（宽高、背景色、外边距、边框样式）
    void SetCommonAttribute(ArkUI\_NodeHandle &node, float width = DEFAULT\_WIDTH, float height = DEFAULT\_HEIGHT,
                            unsigned int color = DEFAULT\_BG\_COLOR, float margin = DEFAULT\_MARGIN)
    {
        SetWidth(node, width);
        SetHeight(node, height);
        SetBackgroundColor(node, color);
        SetMargin(node, margin);
        SetBorderWidth(node, DEFAULT\_BORDER\_WIDTH);
        SetBorderColor(node);
    }
    
2.  接收NODE\_ON\_TOUCH\_INTERCEPT事件。
    
    DragAction主动发起拖拽需通过事件触发，在NODE\_ON\_TOUCH\_INTERCEPT事件中执行发起拖拽所需的操作，通过[targetId](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#oh_arkui_nodeevent_gettargetid)区分不同按钮触发的事件。
    
    nodeAPI->addNodeEventReceiver(dragButton, \[\](ArkUI\_NodeEvent \*event) {
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "RegisterNodeEventForthReceiver called");
        auto eventType = OH\_ArkUI\_NodeEvent\_GetEventType(event);
        auto preDragStatus = OH\_ArkUI\_NodeEvent\_GetPreDragStatus(event);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "eventType = %{public}d, preDragStatus = %{public}d", eventType, preDragStatus);
    
        auto \*dragEvent = OH\_ArkUI\_NodeEvent\_GetDragEvent(event);
        switch (eventType) {
            case NODE\_ON\_TOUCH\_INTERCEPT: {
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_TOUCH\_INTERCEPT EventReceiver");
                // ...
                break;
            }
            default: {
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "UNKNOWN EventReceiver");
                break;
            }
        }
    });
    
3.  起拖阶段设置。
    
    在NODE\_ON\_TOUCH\_INTERCEPT事件中，需要对DragAction进行相关设置。为了主动发起拖拽，需要创建[pixelMap](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-pixelmap-native-h#oh_pixelmapnative_createpixelmap)，设置[ArkUI\_DragPreviewOption](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-arkui-nativemodule-arkui-dragpreviewoption)和跟手点，并将拖拽过程中的文本数据设置到DragAction中。
    
                case NODE\_ON\_TOUCH\_INTERCEPT: {
                    OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_TOUCH\_INTERCEPT EventReceiver");
                    // 创建DragAction
                    action = OH\_ArkUI\_CreateDragActionWithNode(dragButton);
                    OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
                        "OH\_ArkUI\_CreateDragActionWithNode returnValue = %{public}p", action);
                    // 设置pixelMap
                    std::vector<OH\_PixelmapNative \*> pixelVector;
                    SetPixelMap(pixelVector);
                    // 设置DragPreviewOption
                    SetDragPreviewOption();
                    // 设置pointerId、touchPoint
                    PrintDragActionInfos();
                    // 设置unifiedData
                    SetDragActionData();
                    // startDrag
                    int returnValue = OH\_ArkUI\_StartDrag(action);
                    OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
                        "OH\_ArkUI\_StartDrag returnValue = %{public}d",
                        returnValue);
                    if (returnValue != ARKUI\_ERROR\_CODE\_NO\_ERROR && action) {
                        OH\_ArkUI\_DragAction\_UnregisterStatusListener(action);
                        OH\_ArkUI\_DragAction\_Dispose(action);
                        ReleaseDragUdmfData();
                        ReleaseDragPixelMaps();
                        action = nullptr;
                    }
                    break;
                }
                // ...
    void SetDragActionData()
    {
        // 创建OH\_UdmfRecord对象
        OH\_UdmfRecord \*record = OH\_UdmfRecord\_Create();
        // 向OH\_UdmfRecord中添加纯文本类型数据
        OH\_UdsPlainText \*plainText = OH\_UdsPlainText\_Create();
        int returnStatus;
        OH\_UdsPlainText\_SetAbstract(plainText, "this is plainText Abstract example");
        OH\_UdsPlainText\_SetContent(plainText, "this is plainText Content example");
        returnStatus = OH\_UdmfRecord\_AddPlainText(record, plainText);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "dragTest OH\_UdmfRecord\_AddPlainText returnStatus = %{public}d", returnStatus);
        // 创建OH\_UdmfData对象
        ReleaseDragUdmfData();
        OH\_UdmfData \*data = OH\_UdmfData\_Create();
        dragUdmfData = data;
        // 向OH\_UdmfData中添加OH\_UdmfRecord
        returnStatus = OH\_UdmfData\_AddRecord(data, record);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "dragTest OH\_UdmfData\_AddRecord returnStatus = %{public}d", returnStatus);
        int returnValue = OH\_ArkUI\_DragAction\_SetData(action, data);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "OH\_ArkUI\_DragAction\_SetData returnValue = %{public}d", returnValue);
        // 注册拖拽状态监听回调
        OH\_ArkUI\_DragAction\_RegisterStatusListener(action, data, &DragStatusListener);
    }
    
    void SetPixelMap(std::vector<OH\_PixelmapNative \*> &pixelVector)
    {
        uint8\_t data\[960000\];
        size\_t dataSize = 960000;
        for (int i = 0; i < dataSize; i++) {
            data\[i\] = i + 1;
        }
        // 创建参数结构体实例，并设置参数
        OH\_Pixelmap\_InitializationOptions \*createOpts = nullptr;
        OH\_PixelmapInitializationOptions\_Create(&createOpts);
        if (!createOpts) {
            return;
        }
        OH\_PixelmapInitializationOptions\_SetWidth(createOpts, 200U);
        OH\_PixelmapInitializationOptions\_SetHeight(createOpts, 300U);
        OH\_PixelmapInitializationOptions\_SetPixelFormat(createOpts, PIXEL\_FORMAT\_BGRA\_8888);
        OH\_PixelmapInitializationOptions\_SetAlphaType(createOpts, PIXELMAP\_ALPHA\_TYPE\_UNKNOWN);
        // 创建Pixelmap实例
        OH\_PixelmapNative \*pixelmap = nullptr;
        OH\_PixelmapNative\_CreatePixelmap(data, dataSize, createOpts, &pixelmap);
        OH\_PixelmapInitializationOptions\_Release(createOpts);
        if (!pixelmap) {
            return;
        }
        OH\_PixelmapNative\_Flip(pixelmap, true, true);
        pixelVector.push\_back(pixelmap);
        int returnValue = OH\_ArkUI\_DragAction\_SetPixelMaps(action, pixelVector.data(), pixelVector.size());
        if (returnValue == ARKUI\_ERROR\_CODE\_NO\_ERROR) {
            dragPixelMaps.push\_back(pixelmap);
        } else {
            OH\_PixelmapNative\_Release(pixelmap);
        }
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "OH\_ArkUI\_DragAction\_SetPixelMaps returnValue = %{public}d", returnValue);
    }
    
    void SetDragPreviewOption()
    {
        auto \*previewOptions = OH\_ArkUI\_CreateDragPreviewOption();
        OH\_ArkUI\_DragPreviewOption\_SetScaleMode(previewOptions,
            ArkUI\_DragPreviewScaleMode::ARKUI\_DRAG\_PREVIEW\_SCALE\_DISABLED);
        OH\_ArkUI\_DragPreviewOption\_SetDefaultShadowEnabled(previewOptions, true);
        OH\_ArkUI\_DragPreviewOption\_SetDefaultRadiusEnabled(previewOptions, true);
        int returnValue = OH\_ArkUI\_DragAction\_SetDragPreviewOption(action, previewOptions);
        OH\_ArkUI\_DragPreviewOption\_Dispose(previewOptions);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "OH\_ArkUI\_DragAction\_SetDragPreviewOption returnValue = %{public}d", returnValue);
    }
    
    void PrintDragActionInfos()
    {
        // 设置pointerId
        int returnValue = OH\_ArkUI\_DragAction\_SetPointerId(action, 0);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "OH\_ArkUI\_DragAction\_SetPointerId returnValue = %{public}d", returnValue);
        // 设置touchPoint
        returnValue = OH\_ArkUI\_DragAction\_SetTouchPointX(action, 200.0f);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "OH\_ArkUI\_DragAction\_SetTouchPointX returnValue = %{public}d", returnValue);
        returnValue = OH\_ArkUI\_DragAction\_SetTouchPointY(action, 200.0f);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "OH\_ArkUI\_DragAction\_SetTouchPointY returnValue = %{public}d", returnValue);
    }
    
4.  处理NODE\_ON\_DROP事件。
    
    在NODE\_ON\_DROP事件中，应用可以执行与落入阶段相关的操作。通常情况下，需要从DragEvent中获取拖拽过程中传递的数据，DragAction中的拖拽数据也需要通过DragEvent获取。
    
                case NODE\_ON\_DROP: {
                    OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest", "NODE\_ON\_DROP EventReceiver");
                    GetUdmfDataText(dragEvent);
                    break;
                }
                // ...
    void GetUdmfDataText(ArkUI\_DragEvent\* dragEvent)
    {
        // 获取UDMF data
        int returnValue;
        // 创建OH\_UdmfData对象
        OH\_UdmfData \*data = OH\_UdmfData\_Create();
        returnValue = OH\_ArkUI\_DragEvent\_GetUdmfData(dragEvent, data);
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
            "OH\_ArkUI\_DragEvent\_GetUdmfData returnValue = %{public}d", returnValue);
        // 判断OH\_UdmfData是否有对应的类型
        bool resultUdmf = OH\_UdmfData\_HasType(data, UDMF\_META\_PLAIN\_TEXT);
        if (resultUdmf) {
            // 获取OH\_UdmfData的记录
            unsigned int recordsCount = 0;
            OH\_UdmfRecord \*\*records = OH\_UdmfData\_GetRecords(data, &recordsCount);
            // 获取records中的元素
            int returnStatus;
            for (int i = 0; i < recordsCount; i++) {
                // 从OH\_UdmfRecord中获取纯文本类型数据
                OH\_UdsPlainText \*plainTextValue = OH\_UdsPlainText\_Create();
                returnStatus = OH\_UdmfRecord\_GetPlainText(records\[i\], plainTextValue);
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
                    "dragTest OH\_UdmfRecord\_GetPlainText "
                    "returnStatus= %{public}d",
                    returnStatus);
                auto getAbstract = OH\_UdsPlainText\_GetAbstract(plainTextValue);
                auto getContent = OH\_UdsPlainText\_GetContent(plainTextValue);
                OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
                    "OH\_UdsPlainText\_GetAbstract = "
                    "%{public}s, OH\_UdsPlainText\_GetContent = "
                    "%{public}s",
                    getAbstract, getContent);
                // 使用结束后销毁指针
                OH\_UdsPlainText\_Destroy(plainTextValue);
            }
        } else {
            OH\_LOG\_Print(LOG\_APP, LOG\_INFO, 0xFF00U, "dragTest",
                "OH\_UdmfData\_HasType not contain UDMF\_META\_PLAIN\_TEXT");
        }
        OH\_UdmfData\_Destroy(data);
    }