1# Embedding ArkTS Components 2 3 4ArkUI on the native side offers a subset of ArkTS features, which excludes certain capabilities such as declarative UI syntax, custom struct components, and some advanced UI components. 5 6 7For scenarios requiring ArkTS-specific features, ArkUI provides a mechanism to embed ArkTS components using [ComponentContent](../reference/apis-arkui/js-apis-arkui-ComponentContent.md). This involves encapsulating ArkTS components and passing them to the native side, where they are converted into **ArkUI_NodeHandle** objects through the [OH_ArkUI_GetNodeHandleFromNapiValue](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_getnodehandlefromnapivalue) API for component mounting. 8 9 10> **NOTE** 11> 12> - **ArkUI_NodeHandle** objects obtained from **OH_ArkUI_GetNodeHandleFromNapiValue** are for child component parameters only, such as the second parameter of the [addChild](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addchild) API. Using such objects in other scenarios, such as setting attributes with [setAttribute](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#setattribute), will not take effect and will return an error code. 13> 14> - To modify ArkTS components on the native side, construct update data using Node-APIs, and then call the [update](../reference/apis-arkui/js-apis-arkui-ComponentContent.md#update) API of **ComponentContent**. 15> 16> - During the process of [building custom components](ndk-build-custom-components.md), functions such as **measureNode** cannot be used to call components within the ArkTS module. 17 18 19The following example introduces the ArkTS **Refresh** component based on the [Integrating with ArkTS Pages](ndk-access-the-arkts-page.md) section. 20 21 22**Figure 1** Mounting a text list to a Refresh component 23 24 25 26 271. Register the ArkTS component creation function to the native side for it to call, and use the **ComponentContent** capability to encapsulate the creation function. 28 ```ts 29 // MixedModule.ets 30 // Create ArkTS components using the ComponentContent capability. 31 32 import { NodeContent, UIContext, RefreshModifier, ComponentContent } from '@kit.ArkUI'; 33 34 // Define the data object for interaction between the native side and ArkTS. 35 interface NativeRefreshAttribute { 36 isRefreshing: boolean; 37 width?: number; 38 height?: number; 39 backgroundColor?: number; 40 refreshOffset?: number; 41 pullToRefresh?: boolean 42 onRefreshing?: () => void; 43 onOffsetChange?: (offset: number) => void; 44 } 45 46 // Define the format of the input parameters for the @Builder function. 47 interface RefreshAttribute { 48 isRefreshing: boolean; 49 // Optimize attribute settings for performance with Modifier. 50 modifier?: RefreshModifier; 51 slot?: NodeContent; 52 onRefreshing?: () => void; 53 onOffsetChange?: (offset: number) => void; 54 } 55 56 // ComponentContent encapsulates the ArkTS component dependency on the global @Builder function. You can nest @Component decorated custom components within the @Builder function when needed. 57 // The @Builder function provides a way of passing parameters, making it convenient to update parameters later through the update API of ComponentContent. 58 @Builder 59 function mixedRefresh(attribute: RefreshAttribute) { 60 Refresh({ refreshing: attribute.isRefreshing }) { 61 // As a container component, Refresh needs to use the ContentSlot mechanism to reserve a place for child components. 62 ContentSlot(attribute.slot) 63 }.attributeModifier(attribute.modifier) 64 .onRefreshing(() => { 65 console.info("on onRefreshing"); 66 if (attribute.onRefreshing) { 67 console.info("on native onRefreshing"); 68 attribute.onRefreshing(); 69 } 70 }) 71 .onOffsetChange((value: number) => { 72 console.info("on offset change: " + value); 73 if (attribute.onOffsetChange) { 74 console.info("on native onOffsetChange"); 75 attribute.onOffsetChange(value); 76 } 77 }) 78 } 79 80 // Define the return value of the creation function for interaction between the ArkTS side and the native side. 81 interface MixedModuleResult { 82 // Define the encapsulated object for the Refresh construction function, used by the native side to convert to an ArkUI_NodeHandle object. 83 content?: ComponentContent<RefreshAttribute>; 84 // As a container component, Refresh needs to use the ContentSlot mechanism to mount child components from the native side. 85 childSlot?: NodeContent; 86 } 87 88 // Provide an entry function for creating ArkTS components. 89 export function createMixedRefresh(value: NativeRefreshAttribute): MixedModuleResult { 90 console.info("createMixedRefresh"); 91 // Use the AppStorage object to maintain the UI context object when the ability starts. 92 let uiContent = AppStorage.get<UIContext>("context"); 93 let modifier = new RefreshModifier(); 94 if (value.width) { 95 modifier.width(value.width) 96 } 97 if (value.height) { 98 modifier.height(value.height) 99 } 100 if (value.backgroundColor) { 101 modifier.backgroundColor(value.backgroundColor) 102 } 103 if (value.pullToRefresh) { 104 modifier.pullToRefresh(value.pullToRefresh) 105 } 106 if (value.refreshOffset) { 107 modifier.refreshOffset(value.refreshOffset) 108 } 109 // Create a NodeContent slot object for mounting Refresh child components. 110 let nodeSlot = new NodeContent(); 111 // Create the Refresh component using ComponentContent and encapsulate it. 112 let content = new ComponentContent<RefreshAttribute>(uiContent!, wrapBuilder<[RefreshAttribute]>(mixedRefresh), 113 { 114 isRefreshing: value.isRefreshing, 115 modifier: modifier, 116 slot: nodeSlot, 117 onRefreshing: value.onRefreshing, 118 onOffsetChange: value.onOffsetChange 119 }); 120 // Pass the encapsulated object of the Refresh component and its child component slot object to the native side. 121 return { content: content, childSlot: nodeSlot }; 122 } 123 124 // Define the update function for the Refresh component for updating by the native side. 125 // In the update scenario, you need to return the encapsulated object of the Refresh component and its child component slot object to prevent the component from being re-created. 126 export function updateMixedRefresh(refresh: ComponentContent<RefreshAttribute>, childSlot: NodeContent, 127 value: NativeRefreshAttribute): void { 128 let modifier = new RefreshModifier(); 129 if (value.width) { 130 modifier.width(value.width) 131 } 132 if (value.height) { 133 modifier.height(value.height) 134 } 135 if (value.backgroundColor) { 136 modifier.backgroundColor(value.backgroundColor) 137 } 138 if (value.pullToRefresh) { 139 modifier.pullToRefresh(value.pullToRefresh) 140 } 141 if (value.refreshOffset) { 142 modifier.refreshOffset(value.refreshOffset) 143 } 144 // Call the update API of ComponentContent to update. 145 refresh.update({ 146 isRefreshing: value.isRefreshing, 147 modifier: modifier, 148 slot: childSlot, 149 onRefreshing: value.onRefreshing, 150 onOffsetChange: value.onOffsetChange 151 }) 152 } 153 154 ``` 155 1562. Register the creation and update functions with the native side. 157 ```ts 158 // entry.ets 159 import nativeNode from 'libentry.so'; 160 import { NodeContent } from '@kit.ArkUI'; 161 import { createMixedRefresh, updateMixedRefresh } from './MixedModule' 162 163 @Entry 164 @Component 165 struct Index { 166 private rootSlot = new NodeContent(); 167 @State @Watch('changeNativeFlag') showNative: boolean = false; 168 169 aboutToAppear(): void { 170 // Set the UI context. 171 AppStorage.setOrCreate<UIContext>("context", this.getUIContext()); 172 // Set the builder function for mixed mode. 173 nativeNode.registerCreateMixedRefreshNode(createMixedRefresh); 174 nativeNode.registerUpdateMixedRefreshNode(updateMixedRefresh); 175 } 176 177 changeNativeFlag(): void { 178 if (this.showNative) { 179 // Create and mount the NativeModule component. 180 nativeNode.createNativeRoot(this.rootSlot) 181 } else { 182 // Destroy the NativeModule component. 183 nativeNode.destroyNativeRoot() 184 } 185 } 186 187 build() { 188 Column() { 189 Button(this.showNative ? "HideNativeUI" : "ShowNativeUI").onClick(() => { 190 this.showNative = !this.showNative 191 }) 192 Row() { 193 // ArkTS inserts the native component. 194 ContentSlot(this.rootSlot) 195 }.layoutWeight(1) 196 } 197 .width('100%') 198 .height('100%') 199 } 200 } 201 ``` 202 203 ```cpp 204 // native_init.cpp 205 #include "napi/native_api.h" 206 #include "ArkUIMixedRefresh.h" 207 #include "NativeEntry.h" 208 209 EXTERN_C_START 210 static napi_value Init(napi_env env, napi_value exports) { 211 napi_property_descriptor desc[] = { 212 {"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}, 213 // Register the mixed mode creation function. 214 {"registerCreateMixedRefreshNode", nullptr, NativeModule::ArkUIMixedRefresh::RegisterCreateRefresh, nullptr, 215 nullptr, nullptr, napi_default, nullptr}, 216 // Register the mixed mode update function. 217 {"registerUpdateMixedRefreshNode", nullptr, NativeModule::ArkUIMixedRefresh::RegisterUpdateRefresh, nullptr, 218 nullptr, nullptr, napi_default, nullptr}, 219 {"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default, 220 nullptr}}; 221 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 222 return exports; 223 } 224 EXTERN_C_END 225 226 static napi_module demoModule = { 227 .nm_version = 1, 228 .nm_flags = 0, 229 .nm_filename = nullptr, 230 .nm_register_func = Init, 231 .nm_modname = "entry", 232 .nm_priv = ((void *)0), 233 .reserved = {0}, 234 }; 235 236 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } 237 ``` 238 2393. The native side saves the creation and update functions through the Node-API for subsequent calls. 240 ```c 241 // ArkUIMixedRefresh.h 242 // Mixed mode interaction class. 243 244 #ifndef MYAPPLICATION_ARKUIMIXEDREFRESH_H 245 #define MYAPPLICATION_ARKUIMIXEDREFRESH_H 246 247 #include "ArkUIMixedNode.h" 248 249 #include <optional> 250 251 #include <arkui/native_node_napi.h> 252 #include <js_native_api_types.h> 253 254 namespace NativeModule { 255 256 class ArkUIMixedRefresh : public ArkUIMixedNode { 257 public: 258 static napi_value RegisterCreateRefresh(napi_env env, napi_callback_info info); 259 static napi_value RegisterUpdateRefresh(napi_env env, napi_callback_info info); 260 }; 261 262 } // namespace NativeModule 263 264 #endif // MYAPPLICATION_ARKUIMIXEDREFRESH_H 265 ``` 266 267 ```cpp 268 // ArkUIMixedRefresh.cpp 269 // Mixed mode interaction class. 270 271 #include "ArkUIMixedRefresh.h" 272 #include <hilog/log.h> 273 274 namespace NativeModule { 275 namespace { 276 napi_env g_env; 277 napi_ref g_createRefresh; 278 napi_ref g_updateRefresh; 279 } // namespace 280 281 napi_value ArkUIMixedRefresh::RegisterCreateRefresh(napi_env env, napi_callback_info info) { 282 size_t argc = 1; 283 napi_value args[1] = {nullptr}; 284 285 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 286 287 g_env = env; 288 napi_ref refer; 289 // Save the reference after creation to prevent it from being released. 290 napi_create_reference(env, args[0], 1, &refer); 291 292 g_createRefresh = refer; 293 return nullptr; 294 } 295 296 napi_value ArkUIMixedRefresh::RegisterUpdateRefresh(napi_env env, napi_callback_info info) { 297 size_t argc = 1; 298 napi_value args[1] = {nullptr}; 299 300 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 301 302 g_env = env; 303 napi_ref refer; 304 // Save the reference after creation to prevent it from being released. 305 napi_create_reference(env, args[0], 1, &refer); 306 307 g_updateRefresh = refer; 308 return nullptr; 309 } 310 311 } // namespace NativeModule 312 ``` 313 3144. Abstract the base class of components in mixed mode for general logic management. 315 ```c 316 // ArkUIMixedNode.h 317 // Base class for mixed mode. 318 319 #ifndef MYAPPLICATION_ARKUIMIXEDNODE_H 320 #define MYAPPLICATION_ARKUIMIXEDNODE_H 321 322 #include <js_native_api.h> 323 #include <js_native_api_types.h> 324 325 #include "ArkUIBaseNode.h" 326 #include "NativeModule.h" 327 328 namespace NativeModule { 329 330 // Wrap ArkTS Node 331 class ArkUIMixedNode : public ArkUIBaseNode { 332 public: 333 ArkUIMixedNode(ArkUI_NodeHandle handle, napi_env env, napi_ref componentContent) 334 : ArkUIBaseNode(handle), env_(env), componentContent_(componentContent) {} 335 336 // In the base class destructor, the object on the ArkTS side in mixed mode needs to be released. 337 ~ArkUIMixedNode() override { napi_delete_reference(env_, componentContent_); } 338 339 protected: 340 napi_env env_; 341 napi_ref componentContent_; 342 }; 343 344 } // namespace NativeModule 345 346 #endif // MYAPPLICATION_ARKUIMIXEDNODE_H 347 ``` 348 3495. Implement the encapsulation object for the **Refresh** component in mixed mode. 350 ```c 351 // ArkUIMixedRefresh.h 352 // The encapsulation object of Refresh in mixed mode on the native side. 353 354 #ifndef MYAPPLICATION_ARKUIMIXEDREFRESH_H 355 #define MYAPPLICATION_ARKUIMIXEDREFRESH_H 356 357 #include "ArkUIMixedNode.h" 358 #include "ArkUIBaseNode.h" 359 360 #include <optional> 361 362 #include <arkui/native_node_napi.h> 363 #include <js_native_api_types.h> 364 365 namespace NativeModule { 366 367 // Define the interaction data structure between the native side and the ArkTS side. 368 struct NativeRefreshAttribute { 369 std::optional<bool> isRefreshing; 370 std::optional<float> width; 371 std::optional<float> height; 372 std::optional<uint32_t> backgroundColor; 373 std::optional<float> refreshOffset; 374 std::optional<bool> pullToRefresh; 375 std::function<void()> onRefreshing; 376 std::function<void(float)> onOffsetChange; 377 }; 378 379 class ArkUIMixedRefresh : public ArkUIMixedNode { 380 public: 381 // Call the ArkTS method to create the Refresh component. 382 static const std::shared_ptr<ArkUIMixedRefresh> Create(const NativeRefreshAttribute &attribute); 383 384 ArkUIMixedRefresh(ArkUI_NodeHandle handle, ArkUI_NodeContentHandle contentHandle, napi_env env, 385 napi_ref componentContent, napi_ref nodeContent) 386 : ArkUIMixedNode(handle, env, componentContent), contentHandle_(contentHandle), nodeContent_(nodeContent) {} 387 388 ArkUIMixedRefresh() : ArkUIMixedNode(nullptr, nullptr, nullptr) {} 389 390 ~ArkUIMixedRefresh() override { napi_delete_reference(env_, nodeContent_); } // Release the placeholder component slot object for the child node. 391 392 void SetWidth(float width) { attribute_.width = width; } 393 394 void SetHeight(float height) { attribute_.height = height; } 395 396 void SetBackgroundColor(uint32_t color) { attribute_.backgroundColor = color; } 397 398 void SetRefreshState(bool isRefreshing) { attribute_.isRefreshing = isRefreshing; } 399 400 void SetPullToRefresh(bool pullToRefresh) { attribute_.pullToRefresh = pullToRefresh; } 401 402 void SetRefreshOffset(float offset) { attribute_.refreshOffset = offset; } 403 404 void SetRefreshCallback(const std::function<void()> &callback) { attribute_.onRefreshing = callback; } 405 406 void SetOnOffsetChange(const std::function<void(float)> &callback) { attribute_.onOffsetChange = callback; } 407 408 // To avoid frequent cross-language communication, cache property events on the native side and notify in batches. 409 void FlushMixedModeCmd(); 410 411 static napi_value RegisterCreateRefresh(napi_env env, napi_callback_info info); 412 static napi_value RegisterUpdateRefresh(napi_env env, napi_callback_info info); 413 414 protected: 415 void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) override { 416 assert(contentHandle_); 417 // Use NodeContent to mount the component (can be a transformation object of ArkTS on the native side through ComponentContent, or a pure native component) under the ArkTS component. 418 OH_ArkUI_NodeContent_AddNode(contentHandle_, child->GetHandle()); 419 } 420 421 void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) override { 422 assert(contentHandle_); 423 // Use NodeContent to remove the component. 424 OH_ArkUI_NodeContent_RemoveNode(contentHandle_, child->GetHandle()); 425 } 426 427 void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) override { 428 assert(contentHandle_); 429 // Use NodeContent to insert the component. 430 OH_ArkUI_NodeContent_InsertNode(contentHandle_, child->GetHandle(), index); 431 } 432 433 private: 434 // Use the Node-API to create the data structure on the ArkTS side. 435 static napi_value CreateRefreshAttribute(const NativeRefreshAttribute &attribute, void *userData); 436 437 ArkUI_NodeContentHandle contentHandle_; 438 napi_ref nodeContent_; 439 NativeRefreshAttribute attribute_; 440 }; 441 442 } // namespace NativeModule 443 444 #endif // MYAPPLICATION_ARKUIMIXEDREFRESH_H 445 ``` 446 447 Related implementation class description: 448 449 ```c 450 #include "ArkUIMixedRefresh.h" 451 #include <hilog/log.h> 452 453 namespace NativeModule { 454 namespace { 455 napi_env g_env; 456 napi_ref g_createRefresh; 457 napi_ref g_updateRefresh; 458 } // namespace 459 460 // Use the Node-API to create the data structure for interaction with the ArkTS side, used for the creation and update of the Refresh component. 461 napi_value ArkUIMixedRefresh::CreateRefreshAttribute(const NativeRefreshAttribute &attribute, void *userData) { 462 napi_property_descriptor desc[] = { 463 {"width", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData}, 464 {"height", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData}, 465 {"backgroundColor", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData}, 466 {"pullToRefresh", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData}, 467 {"isRefreshing", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData}, 468 {"refreshOffset", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData}, 469 {"onRefreshing", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData}, 470 {"onOffsetChange", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData}, 471 }; 472 if (attribute.width) { 473 napi_value width; 474 napi_create_double(g_env, attribute.width.value(), &width); 475 desc[0].value = width; 476 } 477 if (attribute.height) { 478 napi_value height; 479 napi_create_double(g_env, attribute.height.value(), &height); 480 desc[1].value = height; 481 } 482 if (attribute.backgroundColor) { 483 napi_value backgroundColor; 484 napi_create_uint32(g_env, attribute.backgroundColor.value(), &backgroundColor); 485 desc[2].value = backgroundColor; 486 } 487 if (attribute.pullToRefresh) { 488 napi_value pullToRefresh; 489 napi_create_int32(g_env, attribute.pullToRefresh.value(), &pullToRefresh); 490 desc[3].value = pullToRefresh; 491 } 492 if (attribute.isRefreshing) { 493 napi_value isRefreshing; 494 napi_create_int32(g_env, attribute.isRefreshing.value(), &isRefreshing); 495 desc[4].value = isRefreshing; 496 } 497 if (attribute.refreshOffset) { 498 napi_value refreshOffset; 499 napi_create_double(g_env, attribute.refreshOffset.value(), &refreshOffset); 500 desc[5].value = refreshOffset; 501 } 502 if (attribute.onRefreshing) { 503 OH_LOG_INFO(LOG_APP, "onRefreshing start"); 504 desc[6].method = [](napi_env env, napi_callback_info info) -> napi_value { 505 OH_LOG_INFO(LOG_APP, "onRefreshing callback"); 506 size_t argc = 0; 507 napi_value args[0]; 508 void *data; 509 napi_get_cb_info(env, info, &argc, args, nullptr, &data); 510 auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(data); 511 if (refresh && refresh->attribute_.onRefreshing) { 512 refresh->attribute_.onRefreshing(); 513 } 514 return nullptr; 515 }; 516 } 517 if (attribute.onOffsetChange) { 518 OH_LOG_INFO(LOG_APP, "onOffsetChange start"); 519 desc[7].method = [](napi_env env, napi_callback_info info) -> napi_value { 520 OH_LOG_INFO(LOG_APP, "onOffsetChange callback"); 521 size_t argc = 1; 522 napi_value args[1] = {nullptr}; 523 void *data; 524 napi_get_cb_info(env, info, &argc, args, nullptr, &data); 525 double offset = 0.0; 526 napi_get_value_double(env, args[0], &offset); 527 auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(data); 528 if (refresh && refresh->attribute_.onOffsetChange) { 529 refresh->attribute_.onOffsetChange(offset); 530 } 531 return nullptr; 532 }; 533 } 534 napi_value refreshAttribute = nullptr; 535 auto result = napi_create_object_with_properties(g_env, &refreshAttribute, sizeof(desc) / sizeof(desc[0]), desc); 536 if (result != napi_ok) { 537 return nullptr; 538 } 539 return refreshAttribute; 540 } 541 542 // Create the component on the ArkTS side and save it in the encapsulation object on the native side. 543 const std::shared_ptr<ArkUIMixedRefresh> ArkUIMixedRefresh::Create(const NativeRefreshAttribute &attribute) { 544 napi_handle_scope scope; 545 napi_open_handle_scope(g_env, &scope); 546 auto refresh = std::make_shared<ArkUIMixedRefresh>(); 547 auto refreshAttribute = CreateRefreshAttribute(attribute, refresh.get()); 548 if (refreshAttribute == nullptr) { 549 napi_close_handle_scope(g_env, scope); 550 return nullptr; 551 } 552 napi_value result = nullptr; 553 napi_value argv[1] = {refreshAttribute}; 554 napi_value createRefresh = nullptr; 555 napi_get_reference_value(g_env, g_createRefresh, &createRefresh); 556 // Call the ArkTS Create function to create the ArkTS ComponentContent. 557 napi_call_function(g_env, nullptr, createRefresh, 1, argv, &result); 558 559 // Obtain the ArkTS Refresh component. 560 napi_value componentContent = nullptr; 561 napi_get_named_property(g_env, result, "content", &componentContent); 562 ArkUI_NodeHandle handle; 563 OH_ArkUI_GetNodeHandleFromNapiValue(g_env, componentContent, &handle); 564 assert(handle); 565 // Obtain the child component slot of the ArkTS Refresh component. 566 napi_value nodeContent = nullptr; 567 napi_get_named_property(g_env, result, "childSlot", &nodeContent); 568 ArkUI_NodeContentHandle contentHandle; 569 OH_ArkUI_GetNodeContentFromNapiValue(g_env, nodeContent, &contentHandle); 570 assert(contentHandle); 571 // Save the ArkTS ComponentContent to prevent the object on the ArkTS side from being released and for subsequent updates. 572 napi_ref componentContentRef; 573 napi_create_reference(g_env, componentContent, 1, &componentContentRef); 574 // Save the ArkTS NodeContent to prevent the object on the ArkTS side from being released and for subsequent updates. 575 napi_ref nodeContentRef; 576 napi_create_reference(g_env, nodeContent, 1, &nodeContentRef); 577 // Update the Refresh component related parameters. 578 refresh->handle_ = handle; 579 refresh->env_ = g_env; 580 refresh->componentContent_ = componentContentRef; 581 refresh->nodeContent_ = nodeContentRef; 582 refresh->contentHandle_ = contentHandle; 583 refresh->attribute_ = attribute; 584 return refresh; 585 } 586 // Implementation of the update function. 587 void ArkUIMixedRefresh::FlushMixedModeCmd() { 588 napi_handle_scope scope; 589 napi_open_handle_scope(g_env, &scope); 590 // Create the input parameters for the call to the ArkTS API. 591 auto refreshAttribute = CreateRefreshAttribute(attribute_, this); 592 if (refreshAttribute == nullptr) { 593 napi_close_handle_scope(g_env, scope); 594 return; 595 } 596 // Obtain the remaining two API parameters for the update API. 597 napi_value componentContent = nullptr; 598 napi_get_reference_value(g_env, componentContent_, &componentContent); 599 napi_value nodeContent = nullptr; 600 napi_get_reference_value(g_env, nodeContent_, &nodeContent); 601 602 napi_value argv[3] = {componentContent, nodeContent, refreshAttribute}; 603 napi_value updateRefresh = nullptr; 604 napi_get_reference_value(g_env, g_updateRefresh, &updateRefresh); 605 // Call the ArkTS Update function to update. 606 napi_value result = nullptr; 607 napi_call_function(g_env, nullptr, updateRefresh, 3, argv, &result); 608 } 609 610 napi_value ArkUIMixedRefresh::RegisterCreateRefresh(napi_env env, napi_callback_info info) { 611 size_t argc = 1; 612 napi_value args[1] = {nullptr}; 613 614 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 615 616 g_env = env; 617 napi_ref refer; 618 napi_create_reference(env, args[0], 1, &refer); 619 620 g_createRefresh = refer; 621 return nullptr; 622 } 623 624 napi_value ArkUIMixedRefresh::RegisterUpdateRefresh(napi_env env, napi_callback_info info) { 625 size_t argc = 1; 626 napi_value args[1] = {nullptr}; 627 628 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 629 630 g_env = env; 631 napi_ref refer; 632 napi_create_reference(env, args[0], 1, &refer); 633 634 g_updateRefresh = refer; 635 return nullptr; 636 } 637 638 } // namespace NativeModule 639 640 ``` 641 6426. Use the page structure from the [Integrating with ArkTS Page](ndk-access-the-arkts-page.md) section, and continue with the [timer module simple implementation](ndk-loading-long-list.md), making the **Refresh** component the parent component of the text list. 643 ```c 644 // MixedRefreshExample.h 645 // Sample code for mixed mode. 646 647 #ifndef MYAPPLICATION_MIXEDREFRESHEXAMPLE_H 648 #define MYAPPLICATION_MIXEDREFRESHEXAMPLE_H 649 650 #include "ArkUIBaseNode.h" 651 #include "ArkUIMixedRefresh.h" 652 #include "TextListExample.h" 653 #include "UITimer.h" 654 655 #include <js_native_api_types.h> 656 657 namespace NativeModule { 658 659 std::shared_ptr<ArkUIBaseNode> CreateMixedRefreshList(napi_env env) { 660 auto list = CreateTextListExample(); 661 // Create the Refresh component in mixed mode and mount the List component. 662 NativeRefreshAttribute nativeRefreshAttribute{ 663 .backgroundColor = 0xFF89CFF0, .refreshOffset = 64, .pullToRefresh = true}; 664 auto refresh = ArkUIMixedRefresh::Create(nativeRefreshAttribute); 665 refresh->AddChild(list); 666 667 // Set the event for mixed mode. 668 refresh->SetOnOffsetChange( 669 [](float offset) { OH_LOG_INFO(LOG_APP, "on refresh offset changed: %{public}f", offset); }); 670 refresh->SetRefreshCallback([refreshPtr = refresh.get(), env]() { 671 OH_LOG_INFO(LOG_APP, "on refreshing"); 672 // Start the timer to simulate data acquisition. 673 CreateNativeTimer(env, refreshPtr, 1, [](void *userData, int32_t count) { 674 // Disable the refresh feature after data is obtained. 675 auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(userData); 676 refresh->SetRefreshState(false); 677 refresh->FlushMixedModeCmd(); 678 }); 679 }); 680 681 // Update the event to the ArkTS side. 682 refresh->FlushMixedModeCmd(); 683 return refresh; 684 } 685 686 } // namespace NativeModule 687 688 #endif // MYAPPLICATION_MIXEDREFRESHEXAMPLE_H 689 ``` 690 691 Replace the entry component creation with the pull-to-refresh text list. 692 693 ```c 694 #include "NativeEntry.h" 695 696 #include "ArkUIMixedRefresh.h" 697 #include "MixedRefreshExample.h" 698 #include "TextListExample.h" 699 700 #include <arkui/native_node_napi.h> 701 #include <arkui/native_type.h> 702 #include <js_native_api.h> 703 #include <uv.h> 704 705 namespace NativeModule { 706 707 napi_value CreateNativeRoot(napi_env env, napi_callback_info info) { 708 size_t argc = 1; 709 napi_value args[1] = {nullptr}; 710 711 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 712 713 // Obtain NodeContent. 714 ArkUI_NodeContentHandle contentHandle; 715 OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); 716 NativeEntry::GetInstance()->SetContentHandle(contentHandle); 717 718 // Create a Refresh text list. 719 auto refresh = CreateMixedRefreshList(env); 720 721 // Keep the native side object in the management class to maintain its lifecycle. 722 NativeEntry::GetInstance()->SetRootNode(refresh); 723 return nullptr; 724 } 725 726 napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) { 727 // Release the native side object from the management class. 728 NativeEntry::GetInstance()->DisposeRootNode(); 729 return nullptr; 730 } 731 732 } // namespace NativeModule 733 734 ``` 735