1# 接入ArkTS页面 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @xiang-shouxing--> 5<!--Designer: @xiang-shouxing--> 6<!--Tester: @sally__--> 7<!--Adviser: @HelloCrease--> 8 9## 占位组件 10 11使用NDK接口构建UI界面时,需要在ArkTS页面创建用于挂载NDK接口创建组件的占位组件。占位组件类型为[ContentSlot](../reference/apis-arkui/arkui-ts/ts-components-contentSlot.md),ContentSlot能够绑定一个[NodeContent](../reference/apis-arkui/js-apis-arkui-NodeContent.md)对象,该对象可通过Node-API传递到Native侧挂载显示Native组件。 12 13- NDK配置文件entry/src/main/cpp/types/libentry/oh-package.json5如下。 14 ```ts 15 { 16 "name": "libentry.so", 17 "types": "./index.d.ts", 18 "version": "", 19 "description": "Please describe the basic information." 20 } 21 ``` 22 23- 占位组件和其他ArkTS系统组件使用方法相同。详细代码请参考[示例](#示例)。 24 ```ts 25 import { NodeContent } from '@kit.ArkUI'; 26 import nativeNode from 'libentry.so'; 27 28 @Entry 29 @Component 30 struct Index { 31 // 初始化NodeContent对象。 32 private rootSlot = new NodeContent(); 33 @State @Watch('changeNativeFlag') showNative: boolean = false; 34 35 changeNativeFlag(): void { 36 if (this.showNative) { 37 // 传递NodeContent对象用于Native创建组件的挂载显示 38 nativeNode.createNativeRoot(this.rootSlot) 39 } else { 40 // 销毁NativeModule组件 41 nativeNode.destroyNativeRoot() 42 } 43 } 44 45 build() { 46 Column() { 47 Button(this.showNative ? "HideNativeUI" : "ShowNativeUI").onClick(() => { 48 this.showNative = !this.showNative 49 }) 50 Row() { 51 // 将NodeContent和ContentSlot占位组件绑定。 52 ContentSlot(this.rootSlot) 53 }.layoutWeight(1) 54 } 55 .width('100%') 56 .height('100%') 57 } 58 } 59 ``` 60 61- 占位组件可以通过相关接口在Native侧转化为挂载对象。 62 ``` 63 ArkUI_NodeContentHandle contentHandle; 64 OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); 65 ``` 66 67- 挂载对象提供了相关挂载和卸载组件接口。 68 ``` 69 OH_ArkUI_NodeContent_AddNode(handle_, myNativeNode); 70 OH_ArkUI_NodeContent_RemoveNode(handle_, myNativeNode); 71 ``` 72 73 74## NDK组件模块 75 76NDK提供的UI组件能力如组件创建、树操作、属性设置、事件注册等是通过函数指针结构体(如[ArkUI_NativeNodeAPI_1](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md))进行暴露,该函数指针结构体可以通过[模块查询接口](../reference/apis-arkui/capi-native-interface-h.md#oh_arkui_getmoduleinterface)获取。 77 78> **说明:** 79> - [模块查询接口](../reference/apis-arkui/capi-native-interface-h.md#oh_arkui_getmoduleinterface)带有初始化NDK的逻辑,建议先调用该接口进行全局初始化,再使用NDK进行UI构造。 80 81``` 82ArkUI_NativeNodeAPI_1* arkUINativeNodeApi = nullptr; 83OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi); 84``` 85 86 87在获取到函数指针结构体后,可以使用该结构体内的函数实现相关UI组件操作。 88 89 90- 组件创建和销毁。 91 ``` 92 auto listNode = arkUINativeNodeApi->createNode(ARKUI_NODE_LIST); 93 arkUINativeNodeApi->disposeNode(listNode); 94 ``` 95 96 获取NDK接口支持的组件范围可以通过查询[ArkUI_NodeType](../reference/apis-arkui/capi-native-node-h.md#arkui_nodetype)枚举值。 97 98- 组件树操作。 99 ``` 100 auto parent = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK); 101 auto child = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK); 102 arkUINativeNodeApi->addChild(parent, child); 103 arkUINativeNodeApi->removeChild(parent, child); 104 ``` 105 106- 属性设置。 107 ``` 108 auto stack = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK); 109 ArkUI_NumberValue value[] = {{.f32 = 100}}; 110 ArkUI_AttributeItem item = {value, 1}; 111 arkUINativeNodeApi->setAttribute(stack, NODE_WIDTH, &item); 112 ArkUI_NumberValue value_color[] = {{.u32 = 0xff112233}}; 113 ArkUI_AttributeItem item_color = {value_color, 1}; 114 arkUINativeNodeApi->setAttribute(stack, NODE_BACKGROUND_COLOR, &item); 115 ``` 116 117 获取NDK接口支持的属性范围可以通过查询[ArkUI_NodeAttributeType](../reference/apis-arkui/capi-native-node-h.md#arkui_nodeattributetype)枚举值。 118 119- 事件注册。 120 ``` 121 auto stack = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK); 122 arkUINativeNodeApi->addNodeEventReceiver(stack, [](ArkUI_NodeEvent* event){ 123 // process event 124 }); 125 arkUINativeNodeApi->registerNodeEvent(stack, NODE_ON_CLICK, 0, nullptr); 126 ``` 127 128 获取NDK接口支持的事件范围可以通过查询[ArkUI_NodeEventType](../reference/apis-arkui/capi-native-node-h.md#arkui_nodeeventtype)枚举值。 129 130 131## 示例 132 133下面的示例展示了如何使用ContentSlot挂载Native侧的文本列表。 134 135示例代码的目录结构及其文件说明如下: 136 137``` 138. 139|——cpp 140| |——types 141| | |——libentry 142| | | |——index.d.ts 提供Native和ArkTS侧的桥接方法。 143| |——napi_init.cpp 与index.d.ts对应的桥接方法对接Native侧的定义处。 144| |——NativeEntry.cpp 桥接方法的Native侧实现。 145| |——NativeEntry.h 桥接方法的Native侧定义。 146| |——CMakeList.txt C语言库引用文件。 147| |——ArkuiBaseNode.h 节点封装扩展类。 148| |——ArkuiNode.h 节点封装扩展类。 149| |——ArkuiListNode.h 节点封装扩展类。 150| |——ArkuiListItemNode.h 节点封装扩展类。 151| |——ArkuiTextNode.h 节点封装扩展类。 152| |——NormalTextListExample.h 示例代码文件。 153| 154|——ets 155| |——pages 156| |——entry.ets 应用启动页,加载承载Native的容器。 157| 158``` 159 160**图1** Native文本列表 161 162 163 1641. 在ArkTS页面上声明用于Native页面挂载的占位组件,并在页面创建时通知Native侧创建文本列表。 165 ```ts 166 import nativeNode from 'libentry.so'; 167 import { NodeContent } from '@kit.ArkUI'; 168 169 @Entry 170 @Component 171 struct Index { 172 // 初始化NodeContent对象。 173 private rootSlot = new NodeContent(); 174 @State @Watch('changeNativeFlag') showNative: boolean = false; 175 176 changeNativeFlag(): void { 177 if (this.showNative) { 178 // 传递NodeContent对象用于Native创建组件的挂载显示 179 nativeNode.createNativeRoot(this.rootSlot) 180 } else { 181 // 销毁NativeModule组件 182 nativeNode.destroyNativeRoot() 183 } 184 } 185 186 build() { 187 Column() { 188 Button(this.showNative ? "HideNativeUI" : "ShowNativeUI").onClick(() => { 189 this.showNative = !this.showNative 190 }) 191 Row() { 192 // 将NodeContent和ContentSlot占位组件绑定。 193 ContentSlot(this.rootSlot) 194 }.layoutWeight(1) 195 } 196 .width('100%') 197 .height('100%') 198 } 199 } 200 ``` 201 2022. 使用Native模板创建工程,并在Native侧提供Node-API的桥接方法,实现ArkTS侧的NativeNode模块接口。 203 接口声明。 204 ```ts 205 // entry/src/main/cpp/types/libentry/Index.d.ts 206 207 export const createNativeRoot: (content: Object) => void; 208 export const destroyNativeRoot: () => void; 209 ``` 210 211 Native实现。 212 ```cpp 213 // entry/src/main/cpp/napi_init.cpp 214 #include "napi/native_api.h" 215 #include "NativeEntry.h" 216 217 EXTERN_C_START 218 static napi_value Init(napi_env env, napi_value exports) { 219 // 绑定Native侧的创建组件和销毁组件。 220 napi_property_descriptor desc[] = { 221 {"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}, 222 {"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}}; 223 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 224 return exports; 225 } 226 EXTERN_C_END 227 228 static napi_module demoModule = { 229 .nm_version = 1, 230 .nm_flags = 0, 231 .nm_filename = nullptr, 232 .nm_register_func = Init, 233 .nm_modname = "entry", 234 .nm_priv = ((void *)0), 235 .reserved = {0}, 236 }; 237 238 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } 239 ``` 240 2413. 在NativeEntry.h文件中创建Native界面。 242 ```c 243 // NativeEntry.h 244 245 #ifndef MYAPPLICATION_NATIVEENTRY_H 246 #define MYAPPLICATION_NATIVEENTRY_H 247 248 #include <ArkUIBaseNode.h> 249 #include <arkui/native_type.h> 250 #include <js_native_api_types.h> 251 252 namespace NativeModule { 253 254 napi_value CreateNativeRoot(napi_env env, napi_callback_info info); 255 256 napi_value DestroyNativeRoot(napi_env env, napi_callback_info info); 257 258 // 管理Native组件的生命周期和内存。 259 class NativeEntry { 260 public: 261 static NativeEntry *GetInstance() { 262 static NativeEntry nativeEntry; 263 return &nativeEntry; 264 } 265 266 void SetContentHandle(ArkUI_NodeContentHandle handle) { 267 handle_ = handle; 268 } 269 270 void SetRootNode(const std::shared_ptr<ArkUIBaseNode> &baseNode) { 271 root_ = baseNode; 272 // 添加Native组件到NodeContent上用于挂载显示。 273 OH_ArkUI_NodeContent_AddNode(handle_, root_->GetHandle()); 274 } 275 void DisposeRootNode() { 276 // 从NodeContent上卸载组件并销毁Native组件。 277 OH_ArkUI_NodeContent_RemoveNode(handle_, root_->GetHandle()); 278 root_.reset(); 279 } 280 281 private: 282 std::shared_ptr<ArkUIBaseNode> root_; 283 ArkUI_NodeContentHandle handle_; 284 }; 285 286 } // namespace NativeModule 287 288 #endif // MYAPPLICATION_NATIVEENTRY_H 289 ``` 290 291 对应实现文件。 292 ```cpp 293 // NativeEntry.cpp 294 295 #include <arkui/native_node_napi.h> 296 #include <hilog/log.h> 297 #include <js_native_api.h> 298 #include "NativeEntry.h" 299 #include "NormalTextListExample.h" 300 301 namespace NativeModule { 302 303 napi_value CreateNativeRoot(napi_env env, napi_callback_info info) { 304 size_t argc = 1; 305 napi_value args[1] = {nullptr}; 306 307 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 308 309 // 获取NodeContent 310 ArkUI_NodeContentHandle contentHandle; 311 OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); 312 NativeEntry::GetInstance()->SetContentHandle(contentHandle); 313 314 // 创建文本列表 315 auto list = CreateTextListExample(); 316 317 // 保持Native侧对象到管理类中,维护生命周期。 318 NativeEntry::GetInstance()->SetRootNode(list); 319 return nullptr; 320 } 321 322 napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) { 323 // 从管理类中释放Native侧对象。 324 NativeEntry::GetInstance()->DisposeRootNode(); 325 return nullptr; 326 } 327 328 } // namespace NativeModule 329 ``` 330 331 332 使用NDK 提供的C接口需要在CMakeLists.txt 中增加libace_ndk.z.so 的引用,如下所示,其中entry为工程导出的动态库名称,如当前示例使用的是默认的名称 libentry.so。 333 新增cpp文件后,同样需要在CMakeLists.txt中添加对应cpp文件,如果未配置,对应文件将不会参与编译。 334 335 ``` 336 add_library(entry SHARED napi_init.cpp NativeEntry.cpp) 337 338 target_link_libraries(entry PUBLIC libace_napi.z.so libace_ndk.z.so) 339 ``` 340 3414. 由于NDK接口提供的是C接口,为了使用面向对象的方式简化编程和工程管理,这里建议使用C++进行二次封装,下面示例代码展示了示例界面中所需的列表,文本组件封装类。 342 343 1)获取ArkUI在NDK接口的入口模块[ArkUI_NativeNodeAPI_1](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md),该结构体模块提供了一系列组件创建、树构建、属性设置和事件注册等函数指针。 344 345 ```c 346 // NativeModule.h 347 // 提供获取ArkUI在Native侧模块的封装接口 348 349 #ifndef MYAPPLICATION_NATIVEMODULE_H 350 #define MYAPPLICATION_NATIVEMODULE_H 351 352 #include "napi/native_api.h" 353 #include <arkui/native_node.h> 354 #include <cassert> 355 356 #include <arkui/native_interface.h> 357 358 namespace NativeModule { 359 360 class NativeModuleInstance { 361 public: 362 static NativeModuleInstance *GetInstance() { 363 static NativeModuleInstance instance; 364 return &instance; 365 } 366 367 NativeModuleInstance() { 368 // 获取NDK接口的函数指针结构体对象,用于后续操作。 369 OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi_); 370 assert(arkUINativeNodeApi_); 371 } 372 // 暴露给其他模块使用。 373 ArkUI_NativeNodeAPI_1 *GetNativeNodeAPI() { return arkUINativeNodeApi_; } 374 375 private: 376 ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi_ = nullptr; 377 }; 378 379 } // namespace NativeModule 380 381 #endif // MYAPPLICATION_NATIVEMODULE_H 382 ``` 383 384 2)提供列表,文本组件的基类对象,用于封装通用属性和事件。 385 386 ```c 387 // ArkUIBaseNode.h 388 // 提供组件树操作的基类。 389 390 #ifndef MYAPPLICATION_ARKUIBASENODE_H 391 #define MYAPPLICATION_ARKUIBASENODE_H 392 393 #include <arkui/native_type.h> 394 #include <list> 395 #include <memory> 396 397 #include "NativeModule.h" 398 399 namespace NativeModule { 400 401 class ArkUIBaseNode { 402 public: 403 explicit ArkUIBaseNode(ArkUI_NodeHandle handle) 404 : handle_(handle), nativeModule_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()) {} 405 406 virtual ~ArkUIBaseNode() { 407 // 封装析构函数,实现子节点移除功能。 408 if (!children_.empty()) { 409 for (const auto& child : children_) { 410 nativeModule_->removeChild(handle_, child->GetHandle()); 411 } 412 children_.clear(); 413 } 414 // 封装析构函数,统一回收节点资源。 415 nativeModule_->disposeNode(handle_); 416 } 417 418 void AddChild(const std::shared_ptr<ArkUIBaseNode> &child) { 419 children_.emplace_back(child); 420 OnAddChild(child); 421 } 422 423 void RemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) { 424 children_.remove(child); 425 OnRemoveChild(child); 426 } 427 428 void InsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) { 429 if (index >= children_.size()) { 430 AddChild(child); 431 } else { 432 auto iter = children_.begin(); 433 std::advance(iter, index); 434 children_.insert(iter, child); 435 OnInsertChild(child, index); 436 } 437 } 438 439 ArkUI_NodeHandle GetHandle() const { return handle_; } 440 441 protected: 442 // 针对父容器子类需要重载下面的函数,实现组件挂载和卸载。 443 virtual void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) {} 444 virtual void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) {} 445 virtual void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) {} 446 447 ArkUI_NodeHandle handle_; 448 ArkUI_NativeNodeAPI_1 *nativeModule_ = nullptr; 449 450 private: 451 std::list<std::shared_ptr<ArkUIBaseNode>> children_; 452 }; 453 } // namespace NativeModule 454 455 #endif // MYAPPLICATION_ARKUIBASENODE_H 456 ``` 457 458 ```c 459 // ArkUINode.h 460 // 提供通用属性和事件的封装。 461 462 #ifndef MYAPPLICATION_ARKUINODE_H 463 #define MYAPPLICATION_ARKUINODE_H 464 465 #include "ArkUIBaseNode.h" 466 #include "NativeModule.h" 467 #include <arkui/native_node.h> 468 #include <arkui/native_type.h> 469 470 namespace NativeModule { 471 472 class ArkUINode : public ArkUIBaseNode { 473 public: 474 explicit ArkUINode(ArkUI_NodeHandle handle) : ArkUIBaseNode(handle) {} 475 476 ~ArkUINode() override {} 477 478 // NDK相关通用属性调用封装 479 void SetWidth(float width) { 480 assert(handle_); 481 ArkUI_NumberValue value[] = {{.f32 = width}}; 482 ArkUI_AttributeItem item = {value, 1}; 483 nativeModule_->setAttribute(handle_, NODE_WIDTH, &item); 484 } 485 void SetPercentWidth(float percent) { 486 assert(handle_); 487 ArkUI_NumberValue value[] = {{.f32 = percent}}; 488 ArkUI_AttributeItem item = {value, 1}; 489 nativeModule_->setAttribute(handle_, NODE_WIDTH_PERCENT, &item); 490 } 491 void SetHeight(float height) { 492 assert(handle_); 493 ArkUI_NumberValue value[] = {{.f32 = height}}; 494 ArkUI_AttributeItem item = {value, 1}; 495 nativeModule_->setAttribute(handle_, NODE_HEIGHT, &item); 496 } 497 void SetPercentHeight(float percent) { 498 assert(handle_); 499 ArkUI_NumberValue value[] = {{.f32 = percent}}; 500 ArkUI_AttributeItem item = {value, 1}; 501 nativeModule_->setAttribute(handle_, NODE_HEIGHT_PERCENT, &item); 502 } 503 void SetBackgroundColor(uint32_t color) { 504 assert(handle_); 505 ArkUI_NumberValue value[] = {{.u32 = color}}; 506 ArkUI_AttributeItem item = {value, 1}; 507 nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item); 508 } 509 510 protected: 511 // 组件树操作的实现类对接。 512 void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) override { 513 nativeModule_->addChild(handle_, child->GetHandle()); 514 } 515 void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) override { 516 nativeModule_->removeChild(handle_, child->GetHandle()); 517 } 518 void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) override { 519 nativeModule_->insertChildAt(handle_, child->GetHandle(), index); 520 } 521 }; 522 } // namespace NativeModule 523 524 #endif // MYAPPLICATION_ARKUINODE_H 525 ``` 526 527 3)实现列表组件。 528 529 ```c 530 // ArkUIListNode.h 531 // 提供列表组件的封装。 532 533 #ifndef MYAPPLICATION_ARKUILISTNODE_H 534 #define MYAPPLICATION_ARKUILISTNODE_H 535 536 #include "ArkUINode.h" 537 538 namespace NativeModule { 539 class ArkUIListNode : public ArkUINode { 540 public: 541 ArkUIListNode() 542 : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST)) {} // 创建ArkUI的列表组件。 543 544 ~ArkUIListNode() override {} 545 // List组件的属性NDK接口封装。 546 void SetScrollBarState(bool isShow) { 547 assert(handle_); 548 ArkUI_ScrollBarDisplayMode displayMode = 549 isShow ? ARKUI_SCROLL_BAR_DISPLAY_MODE_ON : ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF; 550 ArkUI_NumberValue value[] = {{.i32 = displayMode}}; 551 ArkUI_AttributeItem item = {value, 1}; 552 nativeModule_->setAttribute(handle_, NODE_SCROLL_BAR_DISPLAY_MODE, &item); 553 } 554 }; 555 } // namespace NativeModule 556 557 #endif // MYAPPLICATION_ARKUILISTNODE_H 558 ``` 559 560 4)实现列表项组件。 561 562 ```c 563 // ArkUIListItemNode.h 564 // 提供列表项的封装类。 565 566 #ifndef MYAPPLICATION_ARKUISTACKNODE_H 567 #define MYAPPLICATION_ARKUISTACKNODE_H 568 569 #include "ArkUINode.h" 570 571 namespace NativeModule { 572 class ArkUIListItemNode : public ArkUINode { 573 public: 574 ArkUIListItemNode() 575 : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM)) {} 576 }; 577 } // namespace NativeModule 578 579 #endif // MYAPPLICATION_ARKUISTACKNODE_H 580 ``` 581 582 5)实现文本组件。 583 584 ```c 585 // ArkUITextNode.h 586 // 实现文本组件的封装类。 587 588 #ifndef MYAPPLICATION_ARKUITEXTNODE_H 589 #define MYAPPLICATION_ARKUITEXTNODE_H 590 591 #include "ArkUINode.h" 592 593 #include <string> 594 595 namespace NativeModule { 596 class ArkUITextNode : public ArkUINode { 597 public: 598 ArkUITextNode() 599 : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_TEXT)) {} 600 // 文本属性NDK接口封装。 601 void SetFontSize(float fontSize) { 602 assert(handle_); 603 ArkUI_NumberValue value[] = {{.f32 = fontSize}}; 604 ArkUI_AttributeItem item = {value, 1}; 605 nativeModule_->setAttribute(handle_, NODE_FONT_SIZE, &item); 606 } 607 void SetFontColor(uint32_t color) { 608 assert(handle_); 609 ArkUI_NumberValue value[] = {{.u32 = color}}; 610 ArkUI_AttributeItem item = {value, 1}; 611 nativeModule_->setAttribute(handle_, NODE_FONT_COLOR, &item); 612 } 613 void SetTextContent(const std::string &content) { 614 assert(handle_); 615 ArkUI_AttributeItem item = {nullptr, 0, content.c_str()}; 616 nativeModule_->setAttribute(handle_, NODE_TEXT_CONTENT, &item); 617 } 618 void SetTextAlign(ArkUI_TextAlignment align) { 619 assert(handle_); 620 ArkUI_NumberValue value[] = {{.i32 = align}}; 621 ArkUI_AttributeItem item = {value, 1}; 622 nativeModule_->setAttribute(handle_, NODE_TEXT_ALIGN, &item); 623 } 624 }; 625 } // namespace NativeModule 626 627 #endif // MYAPPLICATION_ARKUITEXTNODE_H 628 ``` 629 6305. 完善步骤3的CreateTextListExample函数,实现Native文本列表的创建和挂载显示。 631 ```c 632 // NormalTextListExample.h 633 // 自定义NDK接口入口函数。 634 635 #ifndef MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H 636 #define MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H 637 638 #include "ArkUIBaseNode.h" 639 #include "ArkUIListItemNode.h" 640 #include "ArkUIListNode.h" 641 #include "ArkUITextNode.h" 642 #include <hilog/log.h> 643 644 namespace NativeModule { 645 646 std::shared_ptr<ArkUIBaseNode> CreateTextListExample() { 647 // 创建组件并挂载 648 // 1:使用智能指针创建List组件。 649 auto list = std::make_shared<ArkUIListNode>(); 650 list->SetPercentWidth(1); 651 list->SetPercentHeight(1); 652 list->SetScrollBarState(true); 653 // 2:创建ListItem子组件并挂载到List上。 654 for (int32_t i = 0; i < 30; ++i) { 655 auto listItem = std::make_shared<ArkUIListItemNode>(); 656 auto textNode = std::make_shared<ArkUITextNode>(); 657 textNode->SetTextContent(std::to_string(i)); 658 textNode->SetFontSize(16); 659 textNode->SetFontColor(0xFFff00ff); 660 textNode->SetPercentWidth(1); 661 textNode->SetWidth(300); 662 textNode->SetHeight(100); 663 textNode->SetBackgroundColor(0xFFfffacd); 664 textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); 665 listItem->InsertChild(textNode, i); 666 list->AddChild(listItem); 667 } 668 return list; 669 } 670 } // namespace NativeModule 671 672 #endif // MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H 673 ```