1# 嵌入ArkTS组件 2 3 4ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Native侧提供,如声明式UI语法,自定义struct组件,UI高级组件。 5 6 7针对需要使用ArkTS侧独立能力的场景,ArkUI开发框架提供了Native侧嵌入ArkTS组件的能力,该能力依赖[ComponentContent](../reference/apis-arkui/js-apis-arkui-ComponentContent.md)机制,通过ComponentContent完成对ArkTS组件的封装,然后将封装对象转递到Native侧,通过Native侧的[OH_ArkUI_GetNodeHandleFromNapiValue](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_getnodehandlefromnapivalue)接口转化为ArkUI_NodeHandle对象用于Native侧组件挂载使用。 8 9 10> **说明:** 11> 12> - 通过OH_ArkUI_GetNodeHandleFromNapiValue接口获得的ArkUI_NodeHandle对象只能作为子组件参数使用,如[addChild](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addchild)接口的第二个参数,将该对象使用在其他场景下,如[setAttribute](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#setattribute)设置属性将不生效并返回错误码。 13> 14> - 针对Native侧修改ArkTS组件的场景,需要在Native侧通过Node-API方式构建ArkTS侧的更新数据,再通过ComponentContent的[update](../reference/apis-arkui/js-apis-arkui-ComponentContent.md#update)接口更新。 15> 16> - [构建自定义组件](ndk-build-custom-components.md)时,相关函数如measureNode等无法对ArkTS模块内部的组件进行调用。 17 18 19以下示例代码在[接入ArkTS页面](ndk-access-the-arkts-page.md)章节基础上引入ArkTS的Refresh组件。 20 21 22**图1** Refresh组件挂载文本列表 23 24 25 26 271. 注册ArkTS组件创建函数给Native侧,以便Native侧调用,创建函数使用ComponentContent能力进行封装。 28 ```ts 29 // MixedModule.ets 30 // 使用ComponentContent能力创建ArkTS组件 31 32 import { NodeContent, UIContext, RefreshModifier, ComponentContent } from '@kit.ArkUI'; 33 34 // 定义Native侧和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 // 定义@Builder函数的入参格式。 47 interface RefreshAttribute { 48 isRefreshing: boolean; 49 // 属性设置通过Modifier优化性能 50 modifier?: RefreshModifier; 51 slot?: NodeContent; 52 onRefreshing?: () => void; 53 onOffsetChange?: (offset: number) => void; 54 } 55 56 // ComponentContent封装ArkTS组件依赖全局@Builder函数,涉及复杂自定义组件场景,可以在@Builder函数中嵌套@Component自定义组件。 57 // @Builder函数提供入参方式,方便后续通过ComponentContent的update接口进行参数更新。 58 @Builder 59 function mixedRefresh(attribute: RefreshAttribute) { 60 Refresh({ refreshing: attribute.isRefreshing }) { 61 // Refresh作为容器组件,需要使用ContentSlot机制预留子组件占位 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 // 定义创建函数的返回值,用于ArkTS侧和Native侧的交互。 81 interface MixedModuleResult { 82 // 定义针对Refresh构建函数的封装对象,用于Native侧转化为ArkUI_NodeHandle对象。 83 content?: ComponentContent<RefreshAttribute>; 84 // Refresh作为容器组件,需要使用ContentSlot机制挂载Native侧的子组件。 85 childSlot?: NodeContent; 86 } 87 88 // 提供创建ArkTS组件的入口函数。 89 export function createMixedRefresh(value: NativeRefreshAttribute): MixedModuleResult { 90 console.info("createMixedRefresh"); 91 // 通过AppStorage对象在Ability启动的时候保持UI上下文对象。 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 // 创建NodeContent插槽对象用于Refresh子组件挂载。 110 let nodeSlot = new NodeContent(); 111 // 通过ComponentContent创建Refresh组件并将它封装起来。 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 // 将Refresh组件的封装对象及其子组件插槽对象传递给Native侧。 121 return { content: content, childSlot: nodeSlot }; 122 } 123 124 // 定义Refresh组件的更新函数,用于Native侧更新。 125 // 在更新场景下,需要将Refresh组件的封装对象及其子组件插槽对象返回,防止组件重新创建。 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 // 调用ComponentContent的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. 将创建和更新函数注册给Native侧。 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 // 设置uiContext; 171 AppStorage.setOrCreate<UIContext>("context", this.getUIContext()); 172 // 设置混合模式下的builder函数。 173 nativeNode.registerCreateMixedRefreshNode(createMixedRefresh); 174 nativeNode.registerUpdateMixedRefreshNode(updateMixedRefresh); 175 } 176 177 changeNativeFlag(): void { 178 if (this.showNative) { 179 // 创建NativeModule组件挂载 180 nativeNode.createNativeRoot(this.rootSlot) 181 } else { 182 // 销毁NativeModule组件 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插入Native组件。 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 // 注册混合模式创建方法。 214 {"registerCreateMixedRefreshNode", nullptr, NativeModule::ArkUIMixedRefresh::RegisterCreateRefresh, nullptr, 215 nullptr, nullptr, napi_default, nullptr}, 216 // 注册混合模式更新方法。 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. Native侧通过Node-API保存创建和更新函数,用于后续调用。 240 ```c 241 // ArkUIMixedRefresh.h 242 // 混合模式交互类。 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 // 混合模式交互类。 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 // 创建引用之后保存,防止释放。 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 // 创建引用之后保存,防止释放。 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. 抽象混合模式下组件的基类,用于通用逻辑管理。 315 ```c 316 // ArkUIMixedNode.h 317 // 混合模式基类。 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 // 在基类析构的时候需要把混合模式在ArkTS侧的对象释放掉。 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. 实现Refresh组件的混合模式封装对象。 350 ```c 351 // ArkUIMixedRefresh.h 352 // Refresh混合模式在Native侧的封装对象。 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 // 定义Native侧和ArkTS侧的交互数据结构。 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 // 调用ArkTS的方法创建Refresh组件。 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_); } // 释放子节点占位组件插槽对象。 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 // 避免频繁跨语言,在Native侧缓存属性事件,批量通知。 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 // 使用NodeContent挂载组件(可以使用ArkTS在Native侧通过ComponentContent的转化对象,也可以是纯Native组件)到ArkTS组件下面。 418 OH_ArkUI_NodeContent_AddNode(contentHandle_, child->GetHandle()); 419 } 420 421 void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) override { 422 assert(contentHandle_); 423 // 使用NodeContent卸载组件。 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 // 使用NodeContent插入组件。 430 OH_ArkUI_NodeContent_InsertNode(contentHandle_, child->GetHandle(), index); 431 } 432 433 private: 434 // 使用napi接口创建ArkTS侧的数据结构。 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 相关实现类说明: 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 // 使用Napi接口创建与ArkTS侧交互的数据结构,用于Refresh组件的创建和更新。 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 // 创建ArkTS侧的组件并保存在Native侧的封装对象中。 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 // 调用ArkTS的Create函数创建ArkTS的ComponentContent。 557 napi_call_function(g_env, nullptr, createRefresh, 1, argv, &result); 558 559 // 获取ArkTS的Refresh组件。 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 // 获取ArkTS的Refresh组件的子组件插槽。 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 // 保存ArkTS的ComponentContent用于防止ArkTS侧对象释放以及后续的更新。 572 napi_ref componentContentRef; 573 napi_create_reference(g_env, componentContent, 1, &componentContentRef); 574 // 保存ArkTS的NodeContent用于防止ArkTS侧对象释放以及后续的更新。 575 napi_ref nodeContentRef; 576 napi_create_reference(g_env, nodeContent, 1, &nodeContentRef); 577 // 更新Refresh组件相关参数。 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 // 更新函数实现。 587 void ArkUIMixedRefresh::FlushMixedModeCmd() { 588 napi_handle_scope scope; 589 napi_open_handle_scope(g_env, &scope); 590 // 创建调用ArkTS接口入参。 591 auto refreshAttribute = CreateRefreshAttribute(attribute_, this); 592 if (refreshAttribute == nullptr) { 593 napi_close_handle_scope(g_env, scope); 594 return; 595 } 596 // 获取更新接口的剩余两个接口参数。 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 // 调用ArkTS的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. 使用[接入ArkTS页面](ndk-access-the-arkts-page.md)章节的页面结构,并沿用[定时器模块相关简单实现](ndk-loading-long-list.md),将Refresh组件作为文本列表的父组件。 643 ```c 644 // MixedRefreshExample.h 645 // 混合模式示例代码。 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 // 混合模式创建Refresh组件并挂载List组件。 662 NativeRefreshAttribute nativeRefreshAttribute{ 663 .backgroundColor = 0xFF89CFF0, .refreshOffset = 64, .pullToRefresh = true}; 664 auto refresh = ArkUIMixedRefresh::Create(nativeRefreshAttribute); 665 refresh->AddChild(list); 666 667 // 设置混合模式下的事件。 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 // 启动定时器,模拟数据获取。 673 CreateNativeTimer(env, refreshPtr, 1, [](void *userData, int32_t count) { 674 // 数据获取后关闭刷新。 675 auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(userData); 676 refresh->SetRefreshState(false); 677 refresh->FlushMixedModeCmd(); 678 }); 679 }); 680 681 // 更新事件到ArkTS侧。 682 refresh->FlushMixedModeCmd(); 683 return refresh; 684 } 685 686 } // namespace NativeModule 687 688 #endif // MYAPPLICATION_MIXEDREFRESHEXAMPLE_H 689 ``` 690 691 替换入口组件创建为下拉刷新文本列表。 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 // 获取NodeContent 714 ArkUI_NodeContentHandle contentHandle; 715 OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); 716 NativeEntry::GetInstance()->SetContentHandle(contentHandle); 717 718 // 创建Refresh文本列表 719 auto refresh = CreateMixedRefreshList(env); 720 721 // 保持Native侧对象到管理类中,维护生命周期。 722 NativeEntry::GetInstance()->SetRootNode(refresh); 723 return nullptr; 724 } 725 726 napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) { 727 // 从管理类中释放Native侧对象。 728 NativeEntry::GetInstance()->DisposeRootNode(); 729 return nullptr; 730 } 731 732 } // namespace NativeModule 733 734 ``` 735 736