针对List、Grid、WaterFlow、Swiper组件,提供 NodeAdapter 对象替代ArkTS侧的LazyForEach功能,用于按需生成子组件,其中List组件的属性枚举值为NODE_LIST_NODE_ADAPTER,Grid组件的属性枚举值为NODE_GRID_NODE_ADAPTER,WaterFlow组件的属性枚举值为NODE_WATER_FLOW_NODE_ADAPTER,Swiper组件的属性枚举值为NODE_SWIPER_NODE_ADAPTER。
虽然都用于按需生成组件,但不同于ArkTS的LazyForEach,NodeAdapter对象的规格如下:
-
设置了NodeAdapter属性的节点,不再支持addChild等直接添加子组件的接口。子组件完全由NodeAdapter管理,使用属性方法设置NodeAdapter时,会判断父组件是否已经存在子节点,如果父组件已经存在子节点,则设置NodeAdapter操作失败,返回错误码。
-
NodeApdater通过相关事件通知开发者按需生成组件,类似组件事件机制,开发者使用NodeAdapter时要注册 事件监听器 ,在监听器事件中处理逻辑,相关事件通过 ArkUI_NodeAdapterEventType 定义。另外NodeAdapter不会主动释放不在屏幕内显示的组件对象,开发者需要在 NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER 事件中进行组件对象的释放,或者进行缓存复用。下图展示了典型列表滑动场景下的事件触发机制:
以下示例代码针对 接入ArkTS页面 章节代码进行优化,引入懒加载机制实现文本列表:
-
接入ArkTS,参考 接入ArkTS页面 。
-
懒加载适配器相关功能实现。
// ArkUIListItemAdapter
// 用于文本列表懒加载功能代码。
#ifndef MYAPPLICATION_ARKUILISTITEMADAPTER_H
#define MYAPPLICATION_ARKUILISTITEMADAPTER_H
#include <arkui/native_node.h>
#include <stack>
#include <string>
#include <unordered_set>
#include "ArkUIListItemNode.h"
#include "ArkUITextNode.h"
#include "nativeModule.h"
namespace NativeModule {
class ArkUIListItemAdapter {
public:
ArkUIListItemAdapter()
: module_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()), handle_(OH_ArkUI_NodeAdapter_Create()) { // 使用NodeAdapter创建函数。
// 初始化懒加载数据。
for (int32_t i = 0; i < 1000; i++) {
data_.emplace_back(std::to_string(i));
}
// 设置懒加载数据。
OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size());
// 设置懒加载回调事件。
OH_ArkUI_NodeAdapter_RegisterEventReceiver(handle_, this, OnStaticAdapterEvent);
}
~ArkUIListItemAdapter() {
// 释放创建的组件。
while (!cachedItems_.empty()) {
cachedItems_.pop();
}
items_.clear();
// 释放Adapter相关资源。
OH_ArkUI_NodeAdapter_UnregisterEventReceiver(handle_);
OH_ArkUI_NodeAdapter_Dispose(handle_);
}
ArkUI_NodeAdapterHandle GetHandle() const { return handle_; }
void RemoveItem(int32_t index) {
// 删除第index个数据。
data_.erase(data_.begin() + 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 std::string &value) {
data_.insert(data_.begin() + index, 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_, index, 1);
// 更新新的数量。
OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size());
}
void MoveItem(int32_t oldIndex, int32_t newIndex) {
auto temp = data_[oldIndex];
data_.insert(data_.begin() + newIndex, temp);
data_.erase(data_.begin() + oldIndex);
// 移到位置如果未发生可视区域内元素的可见性变化,则不回调事件,反之根据新增和删除场景回调对应的事件。
OH_ArkUI_NodeAdapter_MoveItem(handle_, oldIndex, newIndex);
}
void ReloadItem(int32_t index, const std::string &value) {
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() {
std::reverse(data_.begin(), data_.end());
// 全部重新加载场景下,会回调NODE_ADAPTER_EVENT_ON_GET_NODE_ID接口获取新的组件ID,
// 根据新的组