中国优质的IT技术网站
专业IT技术创作平台
IT职业在线教育平台
HarmonyOS C-API 中 List 组件 adapter 如何使用
微信扫码分享
class MyList { public: MyList() { nodeApi_ = ArkUINativeModule::GetInstance()->GetNodeAPI(); // 初始化数据 for (int32_t i = 0; i < 1000; i++) { data_.emplace_back(std::to_string(i)); } adapter_ = OH_ArkUI_NodeAdapter_Create(); // 设置节点总数为10000。 OH_ArkUI_NodeAdapter_SetTotalNodeCount(1000); // 设置组件创建、销毁回调。 adapterCallback_ = new UserCallback(); adapterCallback_->callback = [this](void* event) { auto* adapterEvent = reinterpret_cast<ArkUI_NodeAdapterEvent*>(event); auto type = OH_ArkUI_NodeAdapterEvent_GetType(adapterEvent); switch (type) { case NODE_ADAPTER_EVENT_ON_GET_NODE_ID: OnGetChildId(adapterEvent); break; case NODE_ADAPTER_EVENT_ON_CREATE_NODE: OnCreateNewChild(adapterEvent); break; case NODE_ADAPTER_EVENT_ON_DISPOSE_NODE: OnDisposeChild(adapterEvent); break; } }; OH_ArkUI_NodeAdapter_RegisterEventReceiver(adapter_, adapterCallback_, [](ArkUI_NodeAdapterEvent* event) { auto* userData = reinterpret_cast<UserCallback*>(OH_ArkUI_NodeAdapterEvent_GetUserData(event)); userData->callback(event); }); // 创建List并设置Adapter和缓存数量。 list_ = nodeApi_->createNode(ARKUI_NODE_LIST); ArkUI_AttributeItem item { nullptr, 0, nullptr, adapter_ }; nodeApi_->setAttribute(list_, NODE_LIST_NODE_ITEM_ADAPTER, &item); ArkUI_NumberValue value[1] = { { .i32 = 10 } }; ArkUI_AttributeItem cacheSize { value, 1 }; nodeApi_->setAttribute(list_, NODE_LIST_CACHE_COUNT, &cacheSize); } ~MyList() { nodeApi_->disposeNode(list_); // 销毁Adapter中所有组件。 ArkUI_NodeHandle* items = nullptr; uint32_t size = 0; OH_ArkUI_NodeAdapter_GetAllItem(adapter_, &items, &size); for (uint32_t i = 0; i < size; i++) { nodeApi_->disposeNode(items[i]); } // 销毁adapter OH_ArkUI_NodeAdapter_Dispose(adapter_); // 销毁缓存组件。 while (!nodePool_.empty()) { nodeApi_->disposeNode(nodePool_.top()); nodePool_.pop(); } delete adapterCallback_; } void ChangeData() { // 删除最后一个数据 data_.pop_back(); // 由于index从0开始计算,删除的位置为999。 // 如果第999个元素保存在NodeAdapter中,那么会将元素删除并回调NODE_ADAPTER_EVENT_ON_DISPOSE_NODE事件通知开发者释放节点资源。 // 如果第999个元素不在NodeAdapter中,不会进行任何操作和回调通知。 OH_ArkUI_NodeAdapter_NotifyItemRemove(adapter_, data_.size(), 1); // 新增一个数据 data_.push_back("new one"); // 由于index从0开始计算,故插入的位置就在999。 // 如果第999个元素位于父组件可视区域中进行展示,那么会回调NODE_ADAPTER_EVENT_ON_GET_NODE_ID事件获取组件标识符, // 随后回调NODE_ADAPTER_EVENT_ON_CREATE_NODE创建节点并保持在NodeAdapter中。 // 如果第999个元素不在展示范围中,不会进行任何操作和回调通知。 OH_ArkUI_NodeAdapter_NotifyItemInsert(adapter_, data_.size(), 1); // 移动位置。 auto iter = data_.begin(); data_.push_back(*iter); data_.erase(iter); // 移动位置不会产生回调。 OH_ArkUI_NodeAdapter_NotifyItemMove(adapter_, 0, data_.size() - 1); // 重载数据。 std::reverse(data_.begin(), data_.end()); // 框架会基于当前可视范围内的所有元素,重新调用NODE_ADAPTER_EVENT_ON_GET_NODE_ID事件获取组件标识符; // 基于新的标识符和老的标识符进行比较,复用标识符相同的元素; // 针对新的标识符调用NODE_ADAPTER_EVENT_ON_CREATE_NODE创建节点并保持在NodeAdapter中; // 针对需要删除的标识符调用NODE_ADAPTER_EVENT_ON_DISPOSE_NODE事件通知开发者释放节点资源。 OH_ArkUI_NodeAdapter_NotifyItemReload(adapter_); } protected: void OnGetChildId(ArkUI_NodeAdapterEvent* event) { auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); // 设置组件唯一标识符。 auto hash = std::hash<std::string>(); OH_ArkUI_NodeAdapterEvent_SetNodeId(event, hash(data_[index])); } void OnCreateNewChild(ArkUI_NodeAdapterEvent* event) { auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); ArkUI_NodeHandle listItem = nullptr; if (!nodePool_.empty()) { // 复用缓存 listItem = nodePool_.top(); nodePool_.pop(); // 更新数据 auto* text = nodeApi_->getFirstChild(listItem); ArkUI_AttributeItem item { nullptr, 0, data_[index].c_str() }; nodeApi_->setAttribute(text, NODE_TEXT_CONTENT, &item); } else { // 重新创建。 auto* text = nodeApi_->createNode(ARKUI_NODE_TEXT); ArkUI_AttributeItem item { nullptr, 0, data_[index].c_str() }; nodeApi_->setAttribute(text, NODE_TEXT_CONTENT, &item); listItem = nodeApi_->createNode(ARKUI_NODE_LIST_ITEM); nodeApi_->addChild(listItem, text); } OH_ArkUI_NodeAdapterEvent_SetCreatedNode(event, listItem); } void OnDisposeChild(ArkUI_NodeAdapterEvent* event) { auto* node = OH_ArkUI_NodeAdapterEvent_GetDisposeNode(event); // 缓存节点 nodePool_.emplace(node); } private: std::vector<std::string> data_; ArkUI_NativeNodeAPI_1* nodeApi_ = nullptr; ArkUI_NodeHandle list_ = nullptr; ArkUI_NodeAdapterHandle adapter_ = nullptr; UserCallback* adapterCallback_ = nullptr; // 节点缓存池,用于回收复用。 std::stack<ArkUI_NodeHandle> nodePool_; }; typedef enum { NODE_LIST_NODE_ITEM_ADAPTER, NODE_LIST_CACHE_COUNT, NODE_SWIPER_NODE_ITEM_ADAPTER, NODE_SWIPER_CACHE_COUNT, NODE_WATER_FLOW_NODE_ITEM_ADAPTER, NODE_WATER_FLOW_CACHE_COUNT, } ArkUI_NodeAttributeType; // 定义组件适配器对象,用于滚动类组件的元素懒加载。 typedef struct ArkUI_NodeAdapter* ArkUI_NodeAdapterHandle; // 定义适配器事件对象。 typedef struct ArkUI_NodeAdapterEvent ArkUI_NodeAdapterEvent; typedef enum { // Adapter适配器挂载到组件上。 NODE_ADAPTER_EVENT_ON_ATTACH_TO_NODE, // Adapter适配器从组件上卸载。 NODE_ADAPTER_EVENT_ON_DETACH_TO_NODE, // 获取组件标识符。 NODE_ADAPTER_EVENT_ON_GET_NODE_ID, // 添加组件到Adapter中。 NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER, // 从Adapter中移除组件。 NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER, } ArkUI_NodeAdapterEventType; ArkUI_NodeAdapterHandle OH_ArkUI_NodeAdapter_Create(); void OH_ArkUI_NodeAdapter_Dispose(ArkUI_NodeAdapterHandle handle); // 设置Adapter中的元素总数。 // 修改数量时默认会触发NotifyItemReloaded通知。 int32_t OH_ArkUI_NodeAdapter_SetTotalNodeCount(ArkUI_NodeAdapterHandle handle, uint32_t size); uint32_t OH_ArkUI_NodeAdapter_GetTotalNodeCount(ArkUI_NodeAdapterHandle handle); // 注册Adapter相关回调事件,如元素需要创建,元素需要销毁等。新注册的覆盖老注册的。 int32_t OH_ArkUI_NodeAdapter_RegisterEventReceiver( ArkUI_NodeAdapterHandle handle, void* userData, void (*receiver)(ArkUI_NodeAdapterEvent* event)); // 反注册事件。 void OH_ArkUI_NodeAdapter_UnregisterEventReceiver(ArkUI_NodeAdapterHandle handle); // 通知Adapter需要进行元素变化。 // 通知适配器数据重载,在数据重载节点会触发NODE_ADAPTER_EVENT_ON_GET_NODE_ID事件获取可视区域和缓存区域组件