• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.cppindex.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![text_list](figures/text_list.gif)
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.so333   新增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   ```