使用列表
====

ArkUI开发框架在NDK接口提供了列表组件，使用列表可以轻松高效地显示结构化、可滚动的信息。列表组件支持控制滚动位置、支持分组显示内容、支持使用[NodeAdapter](#nodeadapter介绍)实现懒加载以提升列表创建性能。

#### 创建列表

参考[接入ArkTS页面](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ndk-access-the-arkts-page)章节实现列表创建。

#### 监听滚动事件

参考[添加事件监听](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ndk-add-component-events)章节实现列表滚动事件监听。

#### 使用懒加载

#### \[h2\]NodeAdapter介绍

NDK提供了NodeAdapter对象替代ArkTS侧的[LazyForEach](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-rendering-control-lazyforeach)功能，用于按需生成子组件，NodeAdapter支持在[List](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list)/[ListItemGroup](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitemgroup)、[Grid](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-grid)、[WaterFlow](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-waterflow)、[Swiper](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper)组件中使用。

*   设置了NodeAdapter属性的节点，不支持直接通过[addChild](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-arkui-nativemodule-arkui-nativenodeapi-1#addchild)等接口添加子组件。子组件完全由NodeAdapter管理，使用属性方法设置NodeAdapter时，会判断父组件是否已经存在子节点，如果父组件已经存在子节点，则设置NodeAdapter操作失败，返回错误码。
    
*   NodeAdapter通过相关事件通知开发者按需生成组件，类似组件事件机制，开发者使用NodeAdapter时要通过[OH\_ArkUI\_NodeAdapter\_RegisterEventReceiver](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#oh_arkui_nodeadapter_registereventreceiver)注册事件监听器，在监听器事件中处理逻辑，相关事件通过[ArkUI\_NodeAdapterEventType](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeadaptereventtype)定义。另外NodeAdapter不会主动释放不在屏幕内显示的组件对象，开发者需要在[NODE\_ADAPTER\_EVENT\_ON\_REMOVE\_NODE\_FROM\_ADAPTER](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#arkui_nodeadaptereventtype)事件中进行组件对象的释放，或者进行缓存复用。下图展示了典型列表滑动场景下的事件触发机制：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/85/v3/I1R-PmO-S5WYUi2MJzlmnQ/zh-cn_image_0000002664207839.png?HW-CC-KV=V1&HW-CC-Date=20260709T132314Z&HW-CC-Expire=86400&HW-CC-Sign=489D91AF8CEAFC04E6183BA0372DBE310D8A30A12937372C31CF3D8A95C38510)
    

以下示例提供了懒加载适配器的实现方法，仅包含主要步骤，完整代码请参考[NdkCreateList](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/ArkUISample/NativeType/NdkCreateList)。

#### \[h2\]实现懒加载适配器

使用ArkUIListItemAdapter类来管理懒加载适配器，在类的构造中创建NodeAdapter对象，并给NodeAdapter对象设置事件监听器，在类的析构函数中，销毁NodeAdapter对象。

ArkUIListItemAdapter类为自定义的通用模板类，模板参数类型可按业务数据和节点模型进行自定义。该模板对外开放“创建子组件”回调，用于按需创建并挂载每个ListItem对应的子组件。该模板还提供“复用ListItem”回调，用于在节点回收后执行状态重置与复用逻辑。

// ArkUIListItemAdapter.h
// 用于文本列表懒加载功能代码。

#ifndef MYAPPLICATION\_ARKUILISTITEMADAPTER\_H
#define MYAPPLICATION\_ARKUILISTITEMADAPTER\_H

#include <algorithm>
#include <arkui/native\_node.h>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <stack>
#include <string>
#include <unordered\_map>
#include <vector>

#include "ArkUIListItemNode.h"
#include "ArkUITextNode.h"
#include "NativeModule.h"

namespace NativeModule {

class IArkUIListItemAdapter {
public:
    virtual ~IArkUIListItemAdapter() = default;
    virtual ArkUI\_NodeAdapterHandle GetHandle() const = 0;
};
template <typename ItemType> class ArkUIListItemAdapterT : public IArkUIListItemAdapter {
public:
    // 创建列表项节点的回调类型。
    using CreateChildCallback = std::function<std::shared\_ptr<ArkUIListItemNode>(const ItemType &item, int32\_t index)>;
    // 复用列表项节点时更新内容的回调类型。
    using ReuseListItemCallback =
        std::function<void(const std::shared\_ptr<ArkUIListItemNode> &listItem, const ItemType &item, int32\_t index)>;
    // 生成节点唯一标识的回调类型。
    using NodeIdCallback = std::function<int64\_t(const ItemType &item, int32\_t index)>;

    // 创建NodeAdapter并初始化数据及各类回调。
    explicit ArkUIListItemAdapterT(std::vector<ItemType> data, CreateChildCallback createChildCallback,
                                   ReuseListItemCallback reuseListItemCallback, NodeIdCallback nodeIdCallback = nullptr)
        : handle\_(OH\_ArkUI\_NodeAdapter\_Create()), data\_(std::move(data)),
          createChildCallback\_(std::move(createChildCallback)),
          reuseListItemCallback\_(std::move(reuseListItemCallback)), nodeIdCallback\_(std::move(nodeIdCallback)) {
        // 设置懒加载数据。
        OH\_ArkUI\_NodeAdapter\_SetTotalNodeCount(handle\_, data\_.size());
        // 设置懒加载回调事件。
        OH\_ArkUI\_NodeAdapter\_RegisterEventReceiver(handle\_, this, OnStaticAdapterEvent);
    }

    ~ArkUIListItemAdapterT() override
    {
        // 释放创建的组件。
        while (!cachedItems\_.empty()) {
            cachedItems\_.pop();
        }
        items\_.clear();
        // 释放Adapter相关资源。
        OH\_ArkUI\_NodeAdapter\_UnregisterEventReceiver(handle\_);
        OH\_ArkUI\_NodeAdapter\_Dispose(handle\_);
    }

    ArkUI\_NodeAdapterHandle GetHandle() const override { return handle\_; }

    const std::vector<ItemType> &GetData() const { return data\_; }

    void SetData(std::vector<ItemType> data)
    {
        data\_ = std::move(data);
        OH\_ArkUI\_NodeAdapter\_SetTotalNodeCount(handle\_, data\_.size());
        OH\_ArkUI\_NodeAdapter\_ReloadAllItems(handle\_);
    }

    void SetNodeIdCallback(NodeIdCallback callback) { nodeIdCallback\_ = std::move(callback); }

    void RemoveItem(size\_t index)
    {
        // 删除第index个数据。
        if (index >= data\_.size()) {
            return;
        }
        data\_.erase(data\_.begin() + static\_cast<std::ptrdiff\_t>(index));
        // 如果index会导致可视区域元素发生可见性变化，则会回调NODE\_ADAPTER\_EVENT\_ON\_REMOVE\_NODE\_FROM\_ADAPTER事件删除元素，
        // 根据是否有新增元素回调NODE\_ADAPTER\_EVENT\_ON\_GET\_NODE\_ID和NODE\_ADAPTER\_EVENT\_ON\_ADD\_NODE\_TO\_ADAPTER事件。
        OH\_ArkUI\_NodeAdapter\_RemoveItem(handle\_, index, 1);
        // 更新新的数量。
        OH\_ArkUI\_NodeAdapter\_SetTotalNodeCount(handle\_, data\_.size());
    }

    void InsertItem(int32\_t index, const ItemType &value)
    {
        int32\_t safeIndex = std::max(0, std::min(index, static\_cast<int32\_t>(data\_.size())));
        data\_.insert(data\_.begin() + safeIndex, value);
        // 如果index会导致可视区域元素发生可见性变化，则会回调NODE\_ADAPTER\_EVENT\_ON\_GET\_NODE\_ID和NODE\_ADAPTER\_EVENT\_ON\_ADD\_NODE\_TO\_ADAPTER事件，
        // 根据是否有删除元素回调NODE\_ADAPTER\_EVENT\_ON\_REMOVE\_NODE\_FROM\_ADAPTER事件。
        OH\_ArkUI\_NodeAdapter\_InsertItem(handle\_, safeIndex, 1);
        // 更新新的数量。
        OH\_ArkUI\_NodeAdapter\_SetTotalNodeCount(handle\_, data\_.size());
    }

    void MoveItem(int32\_t oldIndex, int32\_t newIndex)
    {
        if (!IsValidIndex(oldIndex) || !IsValidIndex(newIndex) || oldIndex == newIndex) {
            return;
        }
        auto temp = data\_\[oldIndex\];
        data\_.insert(data\_.begin() + newIndex, temp);
        int32\_t removeIndex = oldIndex;
        if (newIndex < oldIndex) {
            removeIndex += 1;
        }
        data\_.erase(data\_.begin() + removeIndex);
        // 移到位置如果未发生可视区域内元素的可见性变化，则不回调事件，反之根据新增和删除场景回调对应的事件。
        OH\_ArkUI\_NodeAdapter\_MoveItem(handle\_, oldIndex, newIndex);
    }

    void ReloadItem(int32\_t index, const ItemType &value)
    {
        if (!IsValidIndex(index)) {
            return;
        }
        data\_\[index\] = value;
        // 如果index位于可视区域内，先回调NODE\_ADAPTER\_EVENT\_ON\_REMOVE\_NODE\_FROM\_ADAPTER删除老元素，
        // 再回调NODE\_ADAPTER\_EVENT\_ON\_GET\_NODE\_ID和NODE\_ADAPTER\_EVENT\_ON\_ADD\_NODE\_TO\_ADAPTER事件。
        OH\_ArkUI\_NodeAdapter\_ReloadItem(handle\_, index, 1);
    }

    void ReloadAllItem()
    {
        // 全部重新加载场景下，会回调NODE\_ADAPTER\_EVENT\_ON\_GET\_NODE\_ID接口获取新的组件ID，
        // 根据新的组件ID进行对比，ID不发生变化的进行复用，
        // 针对新增ID的元素，调用NODE\_ADAPTER\_EVENT\_ON\_ADD\_NODE\_TO\_ADAPTER事件创建新的组件，
        // 然后判断老数据中遗留的未使用ID，调用NODE\_ADAPTER\_EVENT\_ON\_REMOVE\_NODE\_FROM\_ADAPTER删除老元素。
        OH\_ArkUI\_NodeAdapter\_ReloadAllItems(handle\_);
    }

private:
    struct ItemEntry {
        std::shared\_ptr<ArkUIListItemNode> listItem = nullptr;
    };

    static void OnStaticAdapterEvent(ArkUI\_NodeAdapterEvent \*event)
    {
        // 获取实例对象，回调实例事件。
        auto \*itemAdapter = reinterpret\_cast<ArkUIListItemAdapterT \*>(OH\_ArkUI\_NodeAdapterEvent\_GetUserData(event));
        if (itemAdapter != nullptr) {
            itemAdapter->OnAdapterEvent(event);
        }
    }

    void OnAdapterEvent(ArkUI\_NodeAdapterEvent \*event)
    {
        // 获取事件类型
        auto type = OH\_ArkUI\_NodeAdapterEvent\_GetType(event);
        switch (type) {
            // Adapter需要添加新元素时获取新元素的唯一标识符
            case NODE\_ADAPTER\_EVENT\_ON\_GET\_NODE\_ID:
                OnNewItemIdCreated(event);
                break;
            // Adapter需要添加新元素时获取新元素的内容
            case NODE\_ADAPTER\_EVENT\_ON\_ADD\_NODE\_TO\_ADAPTER:
                OnNewItemAttached(event);
                break;
            // Adapter将元素移除
            case NODE\_ADAPTER\_EVENT\_ON\_REMOVE\_NODE\_FROM\_ADAPTER:
                OnItemDetached(event);
                break;
            default:
                break;
        }
    }

    // 分配ID给需要显示的Item，用于ReloadAllItems场景的元素diff。
    void OnNewItemIdCreated(ArkUI\_NodeAdapterEvent \*event)
    {
        auto index = OH\_ArkUI\_NodeAdapterEvent\_GetItemIndex(event);
        if (!IsValidIndex(index)) {
            return;
        }
        int64\_t id = nodeIdCallback\_ ? nodeIdCallback\_(data\_\[index\], index) : static\_cast<int64\_t>(index);
        OH\_ArkUI\_NodeAdapterEvent\_SetNodeId(event, id);
    }

    // 需要新的Item显示在可见区域。
    void OnNewItemAttached(ArkUI\_NodeAdapterEvent \*event)
    {
        auto index = OH\_ArkUI\_NodeAdapterEvent\_GetItemIndex(event);
        if (!IsValidIndex(index)) {
            return;
        }

        ItemEntry itemEntry;
        if (!cachedItems\_.empty()) {
            // 使用并更新回收复用的缓存。
            itemEntry = cachedItems\_.top();
            // 释放缓存池的引用。
            cachedItems\_.pop();
            reuseListItemCallback\_(itemEntry.listItem, data\_\[index\], index);
        } else {
            // 创建新的元素。
            itemEntry.listItem = createChildCallback\_(data\_\[index\], index);
        }
        if (itemEntry.listItem == nullptr) {
            itemEntry.listItem = std::make\_shared<ArkUIListItemNode>();
        }

        auto handle = itemEntry.listItem->GetHandle();
        items\_\[handle\] = itemEntry;
        // 设置需要展示的元素。
        OH\_ArkUI\_NodeAdapterEvent\_SetItem(event, handle);
    }
    // Item从可见区域移除。
    void OnItemDetached(ArkUI\_NodeAdapterEvent \*event)
    {
        auto item = OH\_ArkUI\_NodeAdapterEvent\_GetRemovedNode(event);
        auto iter = items\_.find(item);
        if (iter != items\_.end()) {
            // 放置到缓存池中进行回收复用。
            cachedItems\_.push(iter->second);
            items\_.erase(iter);
        }
    }

    bool IsValidIndex(int32\_t index) const { return index >= 0 && index < static\_cast<int32\_t>(data\_.size()); }

    // NodeAdapter实例句柄。
    ArkUI\_NodeAdapterHandle handle\_ = nullptr;
    // 列表数据源。
    std::vector<ItemType> data\_;
    // 创建列表项节点回调。
    CreateChildCallback createChildCallback\_ = nullptr;
    // 复用列表项节点回调。
    ReuseListItemCallback reuseListItemCallback\_ = nullptr;
    // 节点ID生成回调。
    NodeIdCallback nodeIdCallback\_ = nullptr;
    // 管理NodeAdapter生成的元素。
    std::unordered\_map<ArkUI\_NodeHandle, ItemEntry> items\_;

    // 管理回收复用组件池。
    std::stack<ItemEntry> cachedItems\_;
};
} // namespace NativeModule

#endif // MYAPPLICATION\_ARKUILISTITEMADAPTER\_H

#### \[h2\]在列表中应用懒加载适配器

1.  在ArkUIListNode中添加SetLazyAdapter函数，给列表节点设置[NODE\_LIST\_NODE\_ADAPTER](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h-nodeattributetype-scrollablecontainer#node_list_node_adapter)属性，并将NodeAdapter作为属性入参传入。
    
    // ArkUIListNode.h
    // 提供列表组件的封装。
    #ifndef MYAPPLICATION\_ARKUILISTNODE\_H
    #define MYAPPLICATION\_ARKUILISTNODE\_H
    
    #include "ArkUINode.h"
    #include "ArkUIListItemAdapter.h"
    namespace NativeModule {
    class ArkUIListNode : public ArkUINode {
    public:
        ArkUIListNode() // 创建ArkUI的列表组件。
            : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI\_NODE\_LIST)) {}
    
        ~ArkUIListNode() override
        {
            if (nativeModule\_) {
                nativeModule\_->unregisterNodeEvent(handle\_, NODE\_LIST\_ON\_SCROLL\_INDEX);
                if (adapter\_) {
                // 析构的时候卸载adapter下的UI组件。
                    nativeModule\_->resetAttribute(handle\_, NODE\_LIST\_NODE\_ADAPTER);
                    adapter\_.reset();
                }
            }
        }
        // List组件的属性接口封装。
        void SetScrollBarState(bool isShow)
        {
            ArkUI\_ScrollBarDisplayMode displayMode =
                isShow ? ARKUI\_SCROLL\_BAR\_DISPLAY\_MODE\_ON : ARKUI\_SCROLL\_BAR\_DISPLAY\_MODE\_OFF;
            ArkUI\_NumberValue value\[\] = {{.i32 = displayMode}};
            ArkUI\_AttributeItem item = {value, 1};
            nativeModule\_->setAttribute(handle\_, NODE\_SCROLL\_BAR\_DISPLAY\_MODE, &item);
        }
    
        void RegisterOnScrollIndex(const std::function<void(int32\_t index)> &onScrollIndex)
        {
            onScrollIndex\_ = onScrollIndex;
            nativeModule\_->registerNodeEvent(handle\_, NODE\_LIST\_ON\_SCROLL\_INDEX, 0, nullptr);
        }
        // 引入懒加载模块。
        void SetLazyAdapter(const std::shared\_ptr<IArkUIListItemAdapter> &adapter)
        {
            if (!adapter) {
                nativeModule\_->resetAttribute(handle\_, NODE\_LIST\_NODE\_ADAPTER);
                adapter\_.reset();
                return;
            }
            ArkUI\_AttributeItem item{nullptr, 0, nullptr, adapter->GetHandle()};
            nativeModule\_->setAttribute(handle\_, NODE\_LIST\_NODE\_ADAPTER, &item);
            adapter\_ = adapter;
        }
        // ...
    protected:
        void OnNodeEvent(ArkUI\_NodeEvent \*event) override
        {
            auto eventType = OH\_ArkUI\_NodeEvent\_GetEventType(event);
            switch (eventType) {
                case NODE\_LIST\_ON\_SCROLL\_INDEX: {
                    auto index = OH\_ArkUI\_NodeEvent\_GetNodeComponentEvent(event)->data\[0\];
                    if (onScrollIndex\_) {
                        onScrollIndex\_(index.i32);
                    }
                    break;
                }
                default: {
                    break;
                }
            }
        }
    
    private:
        std::function<void(int32\_t index)> onScrollIndex\_;
    
        std::shared\_ptr<IArkUIListItemAdapter> adapter\_;
    };
    } // namespace NativeModule
    
    #endif // MYAPPLICATION\_ARKUILISTNODE\_H
    
2.  创建List使用懒加载的示例代码，调用List节点的SetLazyAdapter接口设置懒加载适配器。
    
    // LazyTextListExample
    // 懒加载列表示例代码。
    
    #ifndef MYAPPLICATION\_LAZYTEXTLISTEXAMPLE1\_H
    #define MYAPPLICATION\_LAZYTEXTLISTEXAMPLE1\_H
    
    #include "ArkUIBaseNode.h"
    #include "ArkUIListNode.h"
    #include "ArkUITextNode.h"
    
    #include <algorithm>
    #include <memory>
    #include <string>
    #include <vector>
    
    namespace NativeModule {
    // ...
    std::shared\_ptr<ArkUIBaseNode> CreateLazyTextListExample1()
    {
        // 创建组件并挂载。
        // 1：创建List组件。
        auto list = std::make\_shared<ArkUIListNode>();
        list->SetPercentWidth(1); // 1：宽度
        list->SetPercentHeight(1); // 1：高度
        auto data = BuildSampleData();
    
        auto adapterWeakHolder = std::make\_shared<std::weak\_ptr<StringAdapter>>();
        // 2：创建ListItem及其子组件的回调。
        auto createChildCallback = \[adapterWeakHolder\](const std::string &item,
                                                       int32\_t index) -> std::shared\_ptr<ArkUIListItemNode> {
            (void)index;
            return BuildListItemNode(item, adapterWeakHolder);
        };
        // 3：复用ListItem的回调。
        auto reuseListItemCallback = \[adapterWeakHolder\](const std::shared\_ptr<ArkUIListItemNode> &listItem,
                                                         const std::string &item, int32\_t index) {
            (void)index;
            ReuseListItemNode(listItem, item, adapterWeakHolder);
        };
    
        auto adapter = std::make\_shared<StringAdapter>(data, createChildCallback, reuseListItemCallback);
        \*adapterWeakHolder = adapter;
        // 4：创建ListItem懒加载组件并挂载到List中。
        list->SetLazyAdapter(adapter);
        return list;
    }
    
    } // namespace NativeModule
    
    #endif // MYAPPLICATION\_LAZYTEXTLISTEXAMPLE1\_H
    
3.  在NativeEntry.cpp中调用List使用懒加载的示例代码。
    
    // NDK接口入口挂载文件。
    
    #include "NativeEntry.h"
    
    #include "LazyTextListExample.h"
    #include "LazyTextListExample1.h"
    
    #include <arkui/native\_node\_napi.h>
    #include <arkui/native\_type.h>
    #include <js\_native\_api.h>
    #include <algorithm>
    #include <memory>
    #include <string>
    #include <uv.h>
    #include <vector>
    
    namespace NativeModule {
    
    // ...
    
    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 = CreateLazyTextListExample();
    
        // 保存Native侧对象到管理类中，维护生命周期。
        NativeEntry::GetInstance()->SetRootNode(node);
        return nullptr;
    }
    
    napi\_value DestroyNativeRoot(napi\_env env, napi\_callback\_info info)
    {
        // 从管理类中释放Native侧对象。
        NativeEntry::GetInstance()->DisposeRootNode();
        return nullptr;
    }
    
    } // namespace NativeModule
    

#### 控制列表滚动位置

1.  控制列表滚动到指定偏移量位置。
    
    // ArkUIListNode.h
    // 提供列表组件的封装。
    // ...
    class ArkUIListNode : public ArkUINode {
    public:
        // ...
        void ScrollTo(float offset)
        {
            ArkUI\_NumberValue value\[\] = {{.f32 = 0}, {.f32 = offset}, {.f32 = 0}};
            ArkUI\_AttributeItem item = {.value = value, .size = 3};
            nativeModule\_->setAttribute(handle\_, NODE\_SCROLL\_OFFSET, &item);
        }
        // ...
    };
    
2.  控制列表滚动到指定元素。
    
    // ArkUIListNode.h
    // 提供列表组件的封装。
    // ...
    class ArkUIListNode : public ArkUINode {
    public:
        // ...
        void ScrollToIndex(int32\_t index)
        {
            ArkUI\_NumberValue value\[\] = {{.i32 = index}};
            ArkUI\_AttributeItem item = {.value = value, .size = 1};
            nativeModule\_->setAttribute(handle\_, NODE\_LIST\_SCROLL\_TO\_INDEX, &item);
        }
        // ...
    };
    
3.  控制列表滚动指定偏移量。
    
    // ArkUIListNode.h
    // 提供列表组件的封装。
    // ...
    class ArkUIListNode : public ArkUINode {
    public:
        // ...
        void ScrollBy(float offset)
        {
            ArkUI\_NumberValue value\[\] = {{.f32 = 0}, {.f32 = offset}};
            ArkUI\_AttributeItem item = {.value = value, .size = 2};
            nativeModule\_->setAttribute(handle\_, NODE\_SCROLL\_BY, &item);
        }
        // ...
    };
    

#### ListItem横划删除

1.  [ListItem](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitem)设置[NODE\_LIST\_ITEM\_SWIPE\_ACTION](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h-nodeattributetype-scrollablecontainer#node_list_item_swipe_action)属性，将[ArkUI\_ListItemSwipeActionOption](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-arkui-nativemodule-arkui-listitemswipeactionoption)对象作为属性参数传入。
    
    // ArkUIListItemNode.h
    // 提供列表项的封装类。
    #ifndef MYAPPLICATION\_ARKUILISTITEMNODE\_H
    #define MYAPPLICATION\_ARKUILISTITEMNODE\_H
    #include "ArkUINode.h"
    namespace NativeModule {
    class ArkUIListItemNode : public ArkUINode {
    public:
        ArkUIListItemNode()
            : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI\_NODE\_LIST\_ITEM)) {}
        ~ArkUIListItemNode() override
        {
            // 销毁ListItemSwipeActionOption实例
            if (swipeAction\_) {
                OH\_ArkUI\_ListItemSwipeActionOption\_Dispose(swipeAction\_);
            }
            // 销毁ListItemSwipeActionItem实例
            if (swipeItem\_) {
                OH\_ArkUI\_ListItemSwipeActionItem\_Dispose(swipeItem\_);
            }
        }
        void SetSwiperAction(std::shared\_ptr<ArkUINode> node)
        {
            swipeContent\_ = node;
            // 创建ListItemSwipeActionItem接口设置的配置项
            swipeItem\_ = OH\_ArkUI\_ListItemSwipeActionItem\_Create();
            // 设置ListItemSwipeActionItem的布局内容
            OH\_ArkUI\_ListItemSwipeActionItem\_SetContent(swipeItem\_, node->GetHandle());
            // 创建ListItemSwipeActionOption接口设置的配置项
            swipeAction\_ = OH\_ArkUI\_ListItemSwipeActionOption\_Create();
            // 设置ListItemSwipeActionItem的右侧（垂直布局）或下方（横向布局）布局内容
            OH\_ArkUI\_ListItemSwipeActionOption\_SetEnd(swipeAction\_, swipeItem\_);
            ArkUI\_AttributeItem Item = {.object = swipeAction\_};
            nativeModule\_->setAttribute(handle\_, NODE\_LIST\_ITEM\_SWIPE\_ACTION, &Item);
        }
        std::shared\_ptr<ArkUINode> GetSwipeContent() const { return swipeContent\_; }
    
    private:
        ArkUI\_ListItemSwipeActionOption \*swipeAction\_ = nullptr;
        ArkUI\_ListItemSwipeActionItem \*swipeItem\_ = nullptr;
        std::shared\_ptr<ArkUINode> swipeContent\_ = nullptr;
    };
    } // namespace NativeModule
    #endif // MYAPPLICATION\_ARKUILISTITEMNODE\_H
    
2.  设置创建ListItem和复用ListItem的回调函数。当创建[ListItem](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitem)时，创建ListItem的划出组件，并绑定点击事件，在点击事件中执行删除数据源操作。ListItem复用时，更新划出组件的绑定事件。
    
    // LazyTextListExample
    // 懒加载列表示例代码。
    
    #ifndef MYAPPLICATION\_LAZYTEXTLISTEXAMPLE1\_H
    #define MYAPPLICATION\_LAZYTEXTLISTEXAMPLE1\_H
    
    #include "ArkUIBaseNode.h"
    #include "ArkUIListNode.h"
    #include "ArkUITextNode.h"
    
    #include <algorithm>
    #include <memory>
    #include <string>
    #include <vector>
    
    namespace NativeModule {
    using StringAdapter = ArkUIListItemAdapterT<std::string>;
    using AdapterWeakHolder = std::shared\_ptr<std::weak\_ptr<StringAdapter>>;
    
    std::vector<std::string> BuildSampleData()
    {
        std::vector<std::string> data;
        data.reserve(1000); // 每个分组预分配1000条数据空间。
        for (int32\_t i = 0; i < 1000; i++) { // 1000：1000条数据空间
            data.emplace\_back(std::to\_string(i));
        }
        return data;
    }
    
    void RegisterDeleteClick(const std::shared\_ptr<ArkUINode> &target, const AdapterWeakHolder &adapterWeakHolder,
        const std::string &item)
    {
        // 为删除区域注册点击事件：通过弱引用获取适配器，避免回调长期持有强引用。
        target->RegisterOnClick(\[adapterWeakHolder, item\](ArkUI\_NodeEvent \*event) {
            (void)event;
            auto adapter = adapterWeakHolder->lock();
            if (!adapter) {
                return;
            }
            // 基于当前数据查找当前 item，确保复用场景下删除的是最新绑定项。
            const auto &currentData = adapter->GetData();
            auto it = std::find(currentData.begin(), currentData.end(), item);
            if (it != currentData.end()) {
                // RemoveItem 需要索引，这里把迭代器位置转换为 size\_t。
                auto removeIndex = static\_cast<size\_t>(std::distance(currentData.begin(), it));
                adapter->RemoveItem(removeIndex);
            }
        });
    }
    
    std::shared\_ptr<ArkUIListItemNode> BuildListItemNode(const std::string &item,
        const AdapterWeakHolder &adapterWeakHolder)
    {
        // 构建一个 ListItem：主文本区域 + 右滑删除操作区。
        auto listItem = std::make\_shared<ArkUIListItemNode>();
    
        // 主内容文本，展示当前数据项。
        auto textNode = std::make\_shared<ArkUITextNode>();
        textNode->SetTextContent(item);
        // ...
        listItem->AddChild(textNode);
    
        // 右滑动作区文本，点击后触发删除当前 item。
        auto swipeNode = std::make\_shared<ArkUITextNode>();
        swipeNode->SetTextContent("del");
        // ...
        RegisterDeleteClick(swipeNode, adapterWeakHolder, item);
        listItem->SetSwiperAction(swipeNode);
        return listItem;
    }
    
    void ReuseListItemNode(const std::shared\_ptr<ArkUIListItemNode> &listItem, const std::string &item,
        const AdapterWeakHolder &adapterWeakHolder)
    {
        auto &children = listItem->GetChildren();
        if (children.empty()) {
            return;
        }
        auto textNode = std::dynamic\_pointer\_cast<ArkUITextNode>(children.front());
        if (textNode) {
            textNode->SetTextContent(item);
            textNode->SetBackgroundColor(0xFFfffacd);
        }
        auto swipeContent = listItem->GetSwipeContent();
        if (swipeContent) {
            RegisterDeleteClick(swipeContent, adapterWeakHolder, item);
        }
    }
    
    // ...
    
    } // namespace NativeModule
    
    #endif // MYAPPLICATION\_LAZYTEXTLISTEXAMPLE1\_H
    
3.  添加新的ListItem时，优先复用已缓存的[ListItem](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitem)实例，并更新其内容；若无可用缓存，则创建新的ListItem。当回调返回空时，创建一个默认的ListItem作为兜底方案。最后，将生成的节点句柄回填至[OH\_ArkUI\_NodeAdapterEvent\_SetItem](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#oh_arkui_nodeadapterevent_setitem)事件中，完成绑定。
    
    // ArkUIListItemAdapter.h
    // ...
    template <typename ItemType> class ArkUIListItemAdapterT : public IArkUIListItemAdapter {
        // ...
        // 需要新的Item显示在可见区域。
        void OnNewItemAttached(ArkUI\_NodeAdapterEvent \*event)
        {
            auto index = OH\_ArkUI\_NodeAdapterEvent\_GetItemIndex(event);
            if (!IsValidIndex(index)) {
                return;
            }
    
            ItemEntry itemEntry;
            if (!cachedItems\_.empty()) {
                // 使用并更新回收复用的缓存。
                itemEntry = cachedItems\_.top();
                // 释放缓存池的引用。
                cachedItems\_.pop();
                reuseListItemCallback\_(itemEntry.listItem, data\_\[index\], index);
            } else {
                // 创建新的元素。
                itemEntry.listItem = createChildCallback\_(data\_\[index\], index);
            }
            if (itemEntry.listItem == nullptr) {
                itemEntry.listItem = std::make\_shared<ArkUIListItemNode>();
            }
    
            auto handle = itemEntry.listItem->GetHandle();
            items\_\[handle\] = itemEntry;
            // 设置需要展示的元素。
            OH\_ArkUI\_NodeAdapterEvent\_SetItem(event, handle);
        }
        // ...
    };
    
4.  ArkUIListItemAdapter中新增RemoveItem，用于删除数据源并且调用[OH\_ArkUI\_NodeAdapter\_RemoveItem](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-node-h#oh_arkui_nodeadapter_removeitem)接口通知框架刷新UI。
    
    // ArkUIListItemAdapter.h
    // ...
    template <typename ItemType> class ArkUIListItemAdapterT : public IArkUIListItemAdapter {
        // ...
        void RemoveItem(size\_t index)
        {
            // 删除第index个数据。
            if (index >= data\_.size()) {
                return;
            }
            data\_.erase(data\_.begin() + static\_cast<std::ptrdiff\_t>(index));
            // 如果index会导致可视区域元素发生可见性变化，则会回调NODE\_ADAPTER\_EVENT\_ON\_REMOVE\_NODE\_FROM\_ADAPTER事件删除元素，
            // 根据是否有新增元素回调NODE\_ADAPTER\_EVENT\_ON\_GET\_NODE\_ID和NODE\_ADAPTER\_EVENT\_ON\_ADD\_NODE\_TO\_ADAPTER事件。
            OH\_ArkUI\_NodeAdapter\_RemoveItem(handle\_, index, 1);
            // 更新新的数量。
            OH\_ArkUI\_NodeAdapter\_SetTotalNodeCount(handle\_, data\_.size());
        }
    
        // ...
    };
    

#### 使用分组列表

1.  分组列表使用[ListItemGroup](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitemgroup)组件实现，ListItemGroup支持添加[header](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitemgroup#listitemgroupoptions对象说明)、[footer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitemgroup#listitemgroupoptions对象说明)设置函数，支持使用懒加载。
    
    // ArkUIListItemGroupNode.h
    
    #ifndef MYAPPLICATION\_ARKUILISTITEMGROUPNODE\_H
    #define MYAPPLICATION\_ARKUILISTITEMGROUPNODE\_H
    
    #include "ArkUINode.h"
    #include "ArkUIListItemAdapter.h"
    
    namespace NativeModule {
    
    class ArkUIListItemGroupNode : public ArkUINode {
    public:
        ArkUIListItemGroupNode()
            : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI\_NODE\_LIST\_ITEM\_GROUP))
        {
        }
    
        void SetHeader(const std::shared\_ptr<ArkUINode> &node)
        {
            if (node) {
                // 创建一个属性项，把节点的句柄放进去，并设置头部
                ArkUI\_AttributeItem item = {.object = node->GetHandle()};
                nativeModule\_->setAttribute(handle\_, NODE\_LIST\_ITEM\_GROUP\_SET\_HEADER, &item);
                header\_ = node;
            } else {
                // 如果传入的是空指针（nullptr），说明要移除已有的头部
                nativeModule\_->resetAttribute(handle\_, NODE\_LIST\_ITEM\_GROUP\_SET\_HEADER);
                header\_.reset();
            }
        }
    
        void SetFooter(const std::shared\_ptr<ArkUINode> &node)
        {
            if (node) {
                // 创建一个属性项，把节点的句柄放进去，并设置尾部
                ArkUI\_AttributeItem item = {.object = node->GetHandle()};
                nativeModule\_->setAttribute(handle\_, NODE\_LIST\_ITEM\_GROUP\_SET\_FOOTER, &item);
                footer\_ = node;
            } else {
                // 如果传入的是空指针（nullptr），说明要移除已有的尾部
                nativeModule\_->resetAttribute(handle\_, NODE\_LIST\_ITEM\_GROUP\_SET\_FOOTER);
                footer\_.reset();
            }
        }
    
        std::shared\_ptr<ArkUINode> GetHeader() const
        {
            return header\_;
        }
    
        std::shared\_ptr<ArkUINode> GetFooter() const
        {
            return footer\_;
        }
    
        // 引入懒加载模块。
        void SetLazyAdapter(const std::shared\_ptr<IArkUIListItemAdapter> &adapter)
        {
            if (!adapter) {
                nativeModule\_->resetAttribute(handle\_, NODE\_LIST\_ITEM\_GROUP\_NODE\_ADAPTER);
                adapter\_.reset();
                return;
            }
            ArkUI\_AttributeItem item{nullptr, 0, nullptr, adapter->GetHandle()};
            nativeModule\_->setAttribute(handle\_, NODE\_LIST\_ITEM\_GROUP\_NODE\_ADAPTER, &item);
            adapter\_ = adapter;
        }
    private:
        std::shared\_ptr<ArkUINode> header\_;
        std::shared\_ptr<ArkUINode> footer\_;
        std::shared\_ptr<IArkUIListItemAdapter> adapter\_;
    };
    }
    #endif // MYAPPLICATION\_ARKUILISTITEMGROUPNODE\_H
    
2.  [List](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list)组件设置吸顶。
    
    // ArkUIListNode.h
    // 提供列表组件的封装。
    // ...
    class ArkUIListNode : public ArkUINode {
        // ...
        void SetSticky(ArkUI\_StickyStyle style)
        {
            ArkUI\_NumberValue value\[\] = {{.i32 = style}};
            ArkUI\_AttributeItem item = {value, 1};
            nativeModule\_->setAttribute(handle\_, NODE\_LIST\_STICKY, &item);
        }
        // ...
    };
    
3.  [List](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list)组件下使用[ListItemGroup](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitemgroup)实现分组列表界面。
    
    // LazyTextListExample.h
    // 懒加载列表示例代码。
    
    #ifndef MYAPPLICATION\_LAZYTEXTLISTEXAMPLE\_H
    #define MYAPPLICATION\_LAZYTEXTLISTEXAMPLE\_H
    
    #include "ArkUIBaseNode.h"
    #include "ArkUIListItemAdapter.h"
    #include "ArkUIListItemGroupNode.h"
    #include "ArkUIListNode.h"
    #include "ArkUITextNode.h"
    
    #include <string>
    #include <vector>
    
    namespace NativeModule {
    // ...
    std::shared\_ptr<ArkUIListItemGroupNode> CreateListItemGroup()
    {
        auto header = std::make\_shared<ArkUITextNode>();
        header->SetTextContent("header");
        header->SetFontSize(16); // 16：字体大小
        header->SetPercentWidth(1); // 1：宽度
        header->SetHeight(50); // 50：高度
        header->SetBackgroundColor(0xFFDCDCDC);
        header->SetTextAlign(ARKUI\_TEXT\_ALIGNMENT\_CENTER);
    
        auto listItemGroup = std::make\_shared<ArkUIListItemGroupNode>();
        listItemGroup->SetHeader(header);
    
        auto groupData = BuildGroupData();
        auto createChildCallback = \[\](const std::string &item, int32\_t index) -> std::shared\_ptr<ArkUIListItemNode> {
            return BuildListItemNode(item, index);
        };
        auto reuseListItemCallback = \[\](const std::shared\_ptr<ArkUIListItemNode> &listItem, const std::string &item,
                                        int32\_t index) {
            ReuseListItemNode(listItem, item, index);
        };
    
        auto adapter = std::make\_shared<ArkUIListItemAdapterT<std::string>>(groupData, createChildCallback,
                                                                             reuseListItemCallback);
        listItemGroup->SetLazyAdapter(adapter);
        return listItemGroup;
    }
    
    std::shared\_ptr<ArkUIBaseNode> CreateLazyTextListExample()
    {
        // 创建组件并挂载。
        // 1：创建List组件。
        auto list = std::make\_shared<ArkUIListNode>();
        list->SetPercentWidth(1); // 1：宽度
        list->SetPercentHeight(1); // 1：高度
        list->SetSticky(ARKUI\_STICKY\_STYLE\_BOTH);
    
        // 2：创建ListItemGroup并挂载到List上。
        for (int32\_t i = 0; i < 3; i++) { // 3：分组数
            list->AddChild(CreateListItemGroup());
        }
        return list;
    }
    
    } // namespace NativeModule
    
    #endif // MYAPPLICATION\_LAZYTEXTLISTEXAMPLE\_H