1# Implementing a List Layout 2 3 4The ArkUI development framework provides list components through NDK APIs, enabling efficient display of structured, scrollable content. List components allow you to control the scroll position, group display content, and use **NodeAdapter** for lazy loading to improve list creation performance. 5 6## Creating a List 7 8For details about how to create a list, see [Integrating with ArkTS Pages](../ui/ndk-access-the-arkts-page.md). 9 10## Listening for Scroll Events 11 12Implement list scroll event monitoring as instructed in the component event monitoring section. 13 14## Implementing Lazy Loading 15 16### NodeAdapter Overview 17 18The NDK provides the [NodeAdapter](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeadapterhandle) object as an alternative to the LazyForEach functionality in ArkTS for on-demand generation of child components. **NodeAdapter** works with **List**, **ListItemGroup**, **Grid**, **WaterFlow**, and **Swiper** components. 19 20- Nodes with **NodeAdapter** set do not support direct child addition APIs like **addChild**. Child components are managed entirely by **NodeAdapter**. If a parent component already has child nodes, setting **NodeAdapter** will fail and return an error code. 21 22- **NodeAdapter** notifies you of on-demand generation of components through relevant events. Similar to the component event mechanism, you need to register an [event listener](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_nodeadapter_registereventreceiver) when using **NodeAdapter** and handle logic in the listener events. Relevant events are defined by [ArkUI_NodeAdapterEventType](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeadaptereventtype). **NodeAdapter** does not actively release off-screen component objects; you must release or cache and reuse component objects in the [NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeadaptereventtype) event. The following image illustrates the event triggering mechanism in a typical list scrolling scenario. 23  24 25 26### Implementing a Lazy Loading Adapter 27 28Use the **ArkUListItemAdapter** class to manage the lazy loading adapter. Create a **NodeAdapter** object in the class constructor and set an event listener for the **NodeAdapter** object. In the class destructor, destroy the **NodeAdapter** object. 29 30 ```c++ 31 // ArkUIListItemAdapter 32 // Code for lazy loading functionality in a text list. 33 34 #ifndef MYAPPLICATION_ARKUILISTITEMADAPTER_H 35 #define MYAPPLICATION_ARKUILISTITEMADAPTER_H 36 37 #include <arkui/native_node.h> 38 #include <stack> 39 #include <string> 40 #include <unordered_set> 41 42 #include "ArkUIListItemNode.h" 43 #include "ArkUITextNode.h" 44 #include "nativeModule.h" 45 46 namespace NativeModule { 47 48 class ArkUIListItemAdapter { 49 public: 50 ArkUIListItemAdapter() 51 : module_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()), handle_(OH_ArkUI_NodeAdapter_Create()) { // Use the NodeAdapter creation function. 52 // Initialize lazy loading data. 53 for (int32_t i = 0; i < 1000; i++) { 54 data_.emplace_back(std::to_string(i)); 55 } 56 // Set lazy loading data. 57 OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); 58 // Register the event receiver for lazy loading. 59 OH_ArkUI_NodeAdapter_RegisterEventReceiver(handle_, this, OnStaticAdapterEvent); 60 } 61 62 ~ArkUIListItemAdapter() { 63 // Release created components. 64 while (!cachedItems_.empty()) { 65 cachedItems_.pop(); 66 } 67 items_.clear(); 68 // Release adapter resources. 69 OH_ArkUI_NodeAdapter_UnregisterEventReceiver(handle_); 70 OH_ArkUI_NodeAdapter_Dispose(handle_); 71 } 72 73 ArkUI_NodeAdapterHandle GetHandle() const { return handle_; } 74 75 void RemoveItem(int32_t index) { 76 // Remove the item at the specified index. 77 data_.erase(data_.begin() + index); 78 // If the index change affects the visibility of items in the visible area, the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event will be triggered to remove the element. 79 // Depending on whether there are new elements, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID or NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER event will be triggered. 80 OH_ArkUI_NodeAdapter_RemoveItem(handle_, index, 1); 81 // Update the total count. 82 OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); 83 } 84 85 void InsertItem(int32_t index, const std::string &value) { 86 data_.insert(data_.begin() + index, value); 87 // If the index change affects the visibility of elements in the visible area, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID and NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER events will be triggered. 88 // If items are removed, the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event will be triggered accordingly. 89 OH_ArkUI_NodeAdapter_InsertItem(handle_, index, 1); 90 // Update the total count. 91 OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); 92 } 93 94 void MoveItem(int32_t oldIndex, int32_t newIndex) { 95 auto temp = data_[oldIndex]; 96 data_.insert(data_.begin() + newIndex, temp); 97 data_.erase(data_.begin() + oldIndex); 98 // If the move changes the visibility of items within the visible area, the corresponding events will be triggered. Otherwise, no event is triggered. 99 OH_ArkUI_NodeAdapter_MoveItem(handle_, oldIndex, newIndex); 100 } 101 102 void ReloadItem(int32_t index, const std::string &value) { 103 data_[index] = value; 104 // If the index is within the visible area, first trigger the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event to remove the old item, 105 // then trigger the NODE_ADAPTER_EVENT_ON_GET_NODE_ID and NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER events. 106 OH_ArkUI_NodeAdapter_ReloadItem(handle_, index, 1); 107 } 108 109 void ReloadAllItem() { 110 std::reverse(data_.begin(), data_.end()); 111 // In the scenario where all items are reloaded, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID event will be triggered to obtain new component IDs, 112 // compare the new component IDs, and reuse those whose IDs have not changed, 113 // for items with new IDs, trigger the NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER event to create new components, 114 // then identify any unused IDs from the old data and call NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER to remove the old items. 115 OH_ArkUI_NodeAdapter_ReloadAllItems(handle_); 116 } 117 118 private: 119 static void OnStaticAdapterEvent(ArkUI_NodeAdapterEvent *event) { 120 // Obtain the instance object and invoke the instance event callback. 121 auto itemAdapter = reinterpret_cast<ArkUIListItemAdapter *>(OH_ArkUI_NodeAdapterEvent_GetUserData(event)); 122 itemAdapter->OnAdapterEvent(event); 123 } 124 125 void OnAdapterEvent(ArkUI_NodeAdapterEvent *event) { 126 auto type = OH_ArkUI_NodeAdapterEvent_GetType(event); 127 switch (type) { 128 case NODE_ADAPTER_EVENT_ON_GET_NODE_ID: 129 OnNewItemIdCreated(event); 130 break; 131 case NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER: 132 OnNewItemAttached(event); 133 break; 134 case NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER: 135 OnItemDetached(event); 136 break; 137 default: 138 break; 139 } 140 } 141 142 // Assign IDs to items that need to be displayed, used for element diffing in the ReloadAllItems scenario. 143 void OnNewItemIdCreated(ArkUI_NodeAdapterEvent *event) { 144 auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); 145 static std::hash<std::string> hashId = std::hash<std::string>(); 146 auto id = hashId(data_[index]); 147 OH_ArkUI_NodeAdapterEvent_SetNodeId(event, id); 148 } 149 150 // Handle the display of new items in the visible area. 151 void OnNewItemAttached(ArkUI_NodeAdapterEvent *event) { 152 auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); 153 ArkUI_NodeHandle handle = nullptr; 154 if (!cachedItems_.empty()) { 155 // Use and update the recycled item from the cache. 156 auto recycledItem = cachedItems_.top(); 157 auto textItem = std::dynamic_pointer_cast<ArkUITextNode>(recycledItem->GetChildren().back()); 158 textItem->SetTextContent(data_[index]); 159 handle = recycledItem->GetHandle(); 160 // Release the reference in the cache pool. 161 cachedItems_.pop(); 162 } else { 163 // Create an element. 164 auto listItem = std::make_shared<ArkUIListItemNode>(); 165 auto textNode = std::make_shared<ArkUITextNode>(); 166 textNode->SetTextContent(data_[index]); 167 textNode->SetFontSize(16); 168 textNode->SetPercentWidth(1); 169 textNode->SetHeight(100); 170 textNode->SetBackgroundColor(0xFFfffacd); 171 textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); 172 listItem->AddChild(textNode); 173 listItem->RegisterOnClick([index]() { OH_LOG_INFO(LOG_APP, "on %{public}d list item click", index); }); 174 handle = listItem->GetHandle(); 175 // Maintain a reference to the text list item. 176 items_.emplace(handle, listItem); 177 } 178 // Set the element to be displayed. 179 OH_ArkUI_NodeAdapterEvent_SetItem(event, handle); 180 } 181 182 // Remove an item from the visible area. 183 void OnItemDetached(ArkUI_NodeAdapterEvent *event) { 184 auto item = OH_ArkUI_NodeAdapterEvent_GetRemovedNode(event); 185 // Place the item in the cache pool for recycling and reuse. 186 cachedItems_.emplace(items_[item]); 187 } 188 189 190 std::vector<std::string> data_; 191 ArkUI_NativeNodeAPI_1 *module_ = nullptr; 192 ArkUI_NodeAdapterHandle handle_ = nullptr; 193 194 // Manage items generated by the NodeAdapter. 195 std::unordered_map<ArkUI_NodeHandle, std::shared_ptr<ArkUIListItemNode>> items_; 196 197 // Manage the component reuse pool. 198 std::stack<std::shared_ptr<ArkUIListItemNode>> cachedItems_; 199 }; 200 201 } // namespace NativeModule 202 203 #endif // MYAPPLICATION_ARKUILISTITEMADAPTER_H 204 ``` 205 206### Applying the Lazy Loading Adapter in a List 207 2081. Add the **SetLazyAdapter** function in **ArkUIListNode** to set the **NODE_LIST_NODE_ADAPTER** attribute for the list node and pass the **NodeAdapter** as an attribute parameter. 209 ```c++ 210 // ArkUIListNode.h 211 // List encapsulation object. 212 213 #ifndef MYAPPLICATION_ARKUILISTNODE_H 214 #define MYAPPLICATION_ARKUILISTNODE_H 215 216 #include "ArkUIListItemAdapter.h" 217 #include "ArkUINode.h" 218 #include <hilog/log.h> 219 220 namespace NativeModule { 221 class ArkUIListNode : public ArkUINode { 222 public: 223 ArkUIListNode() 224 : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST)) {} 225 226 ~ArkUIListNode() override { 227 nativeModule_->unregisterNodeEvent(handle_, NODE_LIST_ON_SCROLL_INDEX); 228 if (adapter_) { 229 // Unload the UI components under the adapter during destruction. 230 nativeModule_->resetAttribute(handle_, NODE_LIST_NODE_ADAPTER); 231 adapter_.reset(); 232 } 233 } 234 235 void SetScrollBarState(bool isShow) { 236 assert(handle_); 237 ArkUI_ScrollBarDisplayMode displayMode = 238 isShow ? ARKUI_SCROLL_BAR_DISPLAY_MODE_ON : ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF; 239 ArkUI_NumberValue value[] = {{.i32 = displayMode}}; 240 ArkUI_AttributeItem item = {value, 1}; 241 nativeModule_->setAttribute(handle_, NODE_SCROLL_BAR_DISPLAY_MODE, &item); 242 } 243 244 void RegisterOnScrollIndex(const std::function<void(int32_t index)> &onScrollIndex) { 245 assert(handle_); 246 onScrollIndex_ = onScrollIndex; 247 nativeModule_->registerNodeEvent(handle_, NODE_LIST_ON_SCROLL_INDEX, 0, nullptr); 248 } 249 // Import the lazy loading module. 250 void SetLazyAdapter(const std::shared_ptr<ArkUIListItemAdapter> &adapter) { 251 assert(handle_); 252 ArkUI_AttributeItem item{nullptr, 0, nullptr, adapter->GetHandle()}; 253 nativeModule_->setAttribute(handle_, NODE_LIST_NODE_ADAPTER, &item); 254 adapter_ = adapter; 255 } 256 257 protected: 258 void OnNodeEvent(ArkUI_NodeEvent *event) override { 259 auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); 260 switch (eventType) { 261 case NODE_LIST_ON_SCROLL_INDEX: { 262 auto index = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event)->data[0]; 263 if (onScrollIndex_) { 264 onScrollIndex_(index.i32); 265 } 266 } 267 default: { 268 } 269 } 270 } 271 272 private: 273 std::function<void(int32_t index)> onScrollIndex_; 274 275 std::shared_ptr<ArkUIListItemAdapter> adapter_; 276 }; 277 } // namespace NativeModule 278 279 #endif // MYAPPLICATION_ARKUILISTNODE_H 280 ``` 281 2822. Create example code for a **List** using lazy loading and call the **SetLazyAdapter** API of the **List** node to set the lazy loading adapter. 283 ```c++ 284 // LazyTextListExample 285 // Example code for a lazy loading text list. 286 287 #ifndef MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H 288 #define MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H 289 290 #include "ArkUIBaseNode.h" 291 #include "ArkUIListNode.h" 292 293 294 namespace NativeModule { 295 296 std::shared_ptr<ArkUIBaseNode> CreateLazyTextListExample(napi_env env) { 297 // Create and mount the component. 298 // 1: Create a List component. 299 auto list = std::make_shared<ArkUIListNode>(); 300 list->SetPercentWidth(1); 301 list->SetPercentHeight(1); 302 // 2: Create a ListItem child component for lazy loading and mount it to the List component. 303 auto adapter = std::make_shared<ArkUIListItemAdapter>(); 304 list->SetLazyAdapter(adapter); 305 return list; 306 } 307 } // namespace NativeModule 308 309 #endif // MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H 310 ``` 311 3123. Call the **List** lazy loading example code in **NativeEntry.cpp**. 313 ```c++ 314 // NDK API entry mounting file. 315 316 #include "NativeEntry.h" 317 318 #include "ArkUIMixedRefresh.h" 319 #include "LazyTextListExample.h" 320 #include "MixedRefreshExample.h" 321 #include "TextListExample.h" 322 323 #include <arkui/native_node_napi.h> 324 #include <arkui/native_type.h> 325 #include <js_native_api.h> 326 #include <uv.h> 327 328 namespace NativeModule { 329 330 331 napi_value CreateNativeRoot(napi_env env, napi_callback_info info) { 332 size_t argc = 1; 333 napi_value args[1] = {nullptr}; 334 335 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 336 337 // Obtain NodeContent. 338 ArkUI_NodeContentHandle contentHandle; 339 OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); 340 NativeEntry::GetInstance()->SetContentHandle(contentHandle); 341 342 // Create a lazy loading text list. 343 auto node = CreateLazyTextListExample(env); 344 345 // Keep the native-side object in the management class to maintain its lifecycle. 346 NativeEntry::GetInstance()->SetRootNode(node); 347 g_env = env; 348 return nullptr; 349 } 350 351 napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) { 352 // Release the native-side object from the management class. 353 NativeEntry::GetInstance()->DisposeRootNode(); 354 return nullptr; 355 } 356 357 } // namespace NativeModule 358 ``` 359## Controlling the List Scroll Position 360 3611. Control the list to scroll to a specified offset position. 362 ```c++ 363 //ArkUIListNode.h 364 // List encapsulation object. 365 class ArkUIListNode: public ArkUINode { 366 //... 367 void ScrollTo(float offset) { 368 ArkUI_NumberValue value[] = {{.f32 =0},{.f32 = offset},{.f32 = 0}}; 369 ArkUI_AttributeItem Item = {.value = value,.size = 3}; 370 nativeModule_->setAttribute(handle_, NODE_SCROLL_OFFSET, &Item); 371 } 372 }; 373 ``` 3742. Control the list to scroll to a specified element. 375 ```c++ 376 //ArkUIListNode.h 377 // List encapsulation object. 378 class ArkUIListNode : public ArkUINode { 379 //... 380 void ScrollToIndex(int32_t index) { 381 ArkUI_NumberValue value[] = {{.i32 = index}}; 382 ArkUI_AttributeItem Item = {.value = value, .size = 1}; 383 nativeModule_->setAttribute(handle_, NODE_LIST_SCROLL_TO_INDEX, &Item); 384 } 385 }; 386 ``` 387 3883. Control the list to scroll by a specified offset. 389 ```c++ 390 //ArkUIListNode.h 391 // List encapsulation object. 392 class ArkUIListNode : public ArkUINode { 393 void ScrollBy(float offset) { 394 ArkUI_NumberValue value[] = {{.f32 =0},{.f32 = offset}}; 395 ArkUI_AttributeItem Item = {.value = value, .size = 2}; 396 nativeModule_->setAttribute(handle_, NODE_SCROLL_BY, &Item); 397 } 398 }; 399 ``` 400## Implementing Swipe-to-Delete for List Items 401 4021. Set the **NODE_LIST_ITEM_SWIPE_ACTION** attribute for **ListItem** and pass the **ArkUI_ListItemSwipeActionOption** object as an attribute parameter. 403 ```c++ 404 // ArkUIListItemNode.h 405 // Encapsulation class for list items. 406 #ifndef MYAPPLICATION_ARKUILISTITEMNODE_H 407 #define MYAPPLICATION_ARKUILISTITEMNODE_H 408 #include "ArkUINode.h" 409 namespace NativeModule{ 410 class ArkUIListItemNode : public ArkUINode { 411 public: 412 ArkUIListItemNode() 413 : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM)) {} 414 ~ArkUIListItemNode() { 415 if(swipeAction_) { 416 OH_ArkUI_ListItemSwipeActionOption_Dispose(swipeAction_); 417 } 418 if (swipeItem_) { 419 OH_ArkUI_ListItemSwipeActionItem_Dispose(swipeItem_); 420 } 421 } 422 void SetSwiperAction(std::shared_ptr<ArkUINode> node) { 423 swipeContent_ = node; 424 swipeItem_ = OH_ArkUI_ListItemSwipeActionItem_Create(); 425 OH_ArkUI_ListItemSwipeActionItem_SetContent(swipeItem_, node->GetHandle()); 426 swipeAction_ = OH_ArkUI_ListItemSwipeActionOption_Create(); 427 OH_ArkUI_ListItemSwipeActionOption_SetEnd(swipeAction_, swipeItem_); 428 ArkUI_AttributeItem Item = {.object= swipeAction_ }; 429 nativeModule_->setAttribute(handle_,NODE_LIST_ITEM_SWIPE_ACTION, &Item); 430 } 431 std::shared_ptr<ArkUINode> GetSwipeContent() const { 432 return swipeContent_; 433 } 434 private: 435 ArkUI_ListItemSwipeActionOption* swipeAction_ = nullptr; 436 ArkUI_ListItemSwipeActionItem* swipeItem_ = nullptr; 437 std::shared_ptr<ArkUINode> swipeContent_ = nullptr; 438 }; 439 }// namespace NativeModule 440 #endif// MYAPPLICATION_ARKUILISTITEMNODE_H 441 ``` 442 4432. When creating a **ListItem**, create the swipe action item for the **ListItem** and bind a click event to perform the data source deletion operation in the click event. When reusing a **ListItem**, update the binding event of the swipe action item. 444 ```c++ 445 // ArkUIListItemAdapter.h 446 class ArkUIListItemAdapter { 447 //... 448 // Handle the display of new items in the visible area. 449 void OnNewItemAttached(ArkUI_NodeAdapterEvent *event) { 450 auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); 451 ArkUI_NodeHandle handle = nullptr; 452 if (!cachedItems_.empty()) { 453 // Use and update the recycled cache. 454 auto recycledItem = cachedItems_.top(); 455 auto textItem = std::dynamic_pointer_cast<ArkUITextNode>(recycledItem->GetChildren().back()); 456 textItem->SetTextContent(data_[index]); 457 handle = recycledItem->GetHandle(); 458 auto swipeContent = recycledItem->GetSwipeContent(); 459 swipeContent->RegisterOnClick([this, data = data_[index]]() { 460 auto it = std::find(data_.begin(), data_.end(), data); 461 if (it != data_.end()) { 462 auto index = std::distance(data_.begin(), it); 463 RemoveItem(index); 464 } 465 }); 466 // Release the reference in the cache pool. 467 cachedItems_.pop(); 468 } else { 469 // Create an element. 470 auto listItem = std::make_shared<ArkUIListItemNode>(); 471 auto textNode = std::make_shared<ArkUITextNode>(); 472 textNode->SetTextContent(data_[index]); 473 textNode->SetFontSize(16); 474 textNode->SetPercentWidth(1); 475 textNode->SetHeight(100); 476 textNode->SetBackgroundColor(0xFFfffacd); 477 textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); 478 listItem->AddChild(textNode); 479 // Create the swipe action item for the ListItem. 480 auto swipeNode = std::make_shared<ArkUITextNode>(); 481 swipeNode->SetTextContent("del"); 482 swipeNode->SetFontSize(16); 483 swipeNode->SetFontColor(0xFFFFFFFF); 484 swipeNode->SetWidth(100); 485 swipeNode->SetHeight(100); 486 swipeNode->SetBackgroundColor(0xFFFF0000); 487 swipeNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); 488 swipeNode->RegisterOnClick([this, data = data_[index]]() { 489 auto it = std::find(data_.begin(), data_.end(), data); 490 if (it != data_.end()) { 491 auto index = std::distance(data_.begin(), it); 492 RemoveItem(index); 493 } 494 }); 495 listItem->SetSwiperAction(swipeNode); 496 handle = listItem->GetHandle(); 497 // Maintain a reference to the text list item. 498 items_.emplace(handle, listItem); 499 } 500 // Set the element to be displayed. 501 OH_ArkUI_NodeAdapterEvent_SetItem(event, handle); 502 } 503 } 504 ``` 5053. Add **RemoveItem** in **ArkUIListItemAdapter** to delete the data source and call the **OH_ArkUI_NodeAdapter_RemoveItem** API to instruct the framework to update the UI. 506 ```c++ 507 // ArkUIListItemAdapter.h 508 class ArkUIListItemAdapter { 509 //... 510 void RemoveItem(size_t index) { 511 // Remove the item at the specified index. 512 data_.erase(data_.begin() + index); 513 // If the index change affects the visibility of items in the visible area, the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event will be triggered to remove the element. 514 // Depending on whether there are new elements, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID or NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER event will be triggered. 515 OH_ArkUI_NodeAdapter_RemoveItem(handle_, index, 1); 516 // Update the total count. 517 OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); 518 } 519 }; 520 ``` 521## Using a Grouped List 5221. Implement a grouped list using the **ListItemGroup** component, which supports features to add headers and footers and use lazy loading. 523 ```c++ 524 // ArkUIListItemGroupNode.h 525 526 #ifndef MYAPPLICATION_ARKUILISTITEMGROUPNODE_H 527 #define MYAPPLICATION_ARKUILISTITEMGROUPNODE_H 528 #include "ArkUINode.h" 529 #include "ArkUIListItemAdapter.h" 530 namespace NativeModule{ 531 class ArkUIListItemGroupNode : public ArkUINode { 532 public: 533 ArkUIListItemGroupNode() 534 : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM_GROUP)) {} 535 void SetHeader(std::shared_ptr<ArkUINode> node) { 536 if (node) { 537 ArkUI_AttributeItem Item = {.object = node->GetHandle()}; 538 nativeModule_->setAttribute(handle_, NODE_LIST_ITEM_GROUP_SET_HEADER, &Item); 539 } else { 540 nativeModule_->resetAttribute(handle_, NODE_LIST_ITEM_GROUP_SET_HEADER); 541 } 542 } 543 void SetFooter(std::shared_ptr<ArkUINode> node) { 544 if (node) { 545 ArkUI_AttributeItem Item = {.object= node->GetHandle()}; 546 nativeModule_->setAttribute(handle_, NODE_LIST_ITEM_GROUP_SET_FOOTER, &Item); 547 } else { 548 nativeModule_->resetAttribute(handle_, NODE_LIST_ITEM_GROUP_SET_FOOTER); 549 } 550 } 551 std::shared_ptr<ArkUINode> GetHeader() const { 552 return header_; 553 } 554 std::shared_ptr<ArkUINode> GetFooter() const { 555 return footer_; 556 } 557 // Import the lazy loading module. 558 void SetLazyAdapter(const std::shared_ptr<ArkUIListItemAdapter> &adapter) { 559 assert(handle_); 560 ArkUI_AttributeItem item{nullptr,0, nullptr, adapter->GetHandle()}; 561 nativeModule_->setAttribute(handle_, NODE_LIST_ITEM_GROUP_NODE_ADAPTER, &item); 562 adapter_ = adapter; 563 } 564 private: 565 std::shared_ptr<ArkUINode> header_; 566 std::shared_ptr<ArkUINode> footer_; 567 std::shared_ptr<ArkUIListItemAdapter> adapter_; 568 }; 569 }// namespace NativeModule 570 #endif//MYAPPLICATION_ARKUILISTITEMGROUPNODE_H 571 ``` 5722. Set the sticky header for the **List** component. 573 ```c++ 574 // ArkUIListNode.h 575 // List encapsulation object. 576 class ArkUIListNode : public ArkUINode{ 577 //... 578 void SetSticky(ArkUI_StickyStyle style) { 579 assert(handle_); 580 ArkUI_NumberValue value[] = {{.i32 = style}}; 581 ArkUI_AttributeItem item = {value, 1}; 582 nativeModule_->setAttribute(handle_, NODE_LIST_STICKY, &item); 583 } 584 }; 585 ``` 5863. Implement a grouped list UI using **ListItemGroup** under the **List** component. 587 ```c++ 588 // LazyTextListExample.h 589 // Example code for a lazy loading text list. 590 #ifndef MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H 591 #define MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H 592 #include "ArkUIBaseNode.h" 593 #include "ArkUIListNode.h" 594 #include "ArkUIListItemGroupNode.h" 595 namespace NativeModule { 596 std::shared_ptr<ArkUIBaseNode> CreateLazyTextListExample() { 597 // Create and mount the component. 598 // 1: Create a List component. 599 auto list = std::make_shared<ArkUIListNode>(); 600 list->SetPercentWidth(1); 601 list->SetPercentHeight(1); 602 // Set the sticky header. 603 list->SetSticky(ARKUI_STICKY_STYLE_BOTH); 604 // 2: Create a ListItemGroup and mount it to the List. 605 for (int32_t i = 0; i < 3; i++) { 606 auto header = std::make_shared<ArkUITextNode>(); 607 header->SetTextContent("header"); 608 header->SetFontSize(16); 609 header->SetPercentWidth(1); 610 header->SetHeight(50); 611 header->SetBackgroundColor(0xFFDCDCDC); 612 header->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); 613 auto listItemGroup = std::make_shared<ArkUIListItemGroupNode>(); 614 listItemGroup->SetHeader(header); 615 auto adapter = std::make_shared<ArkUIListItemAdapter>(4); 616 listItemGroup->SetLazyAdapter(adapter); 617 list->AddChild(listItemGroup); 618 } 619 return list; 620 } 621 }// namespace NativeModule 622 #endif// MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H 623 ``` 624