当前位置: 首页 > news >正文

鸿蒙NEXT系列之鸿蒙NDK UI 初探

鸿蒙NDK UI初探

  • 〇、前言
  • 一、NDK UI 整体架构
  • 二、实现 NDK UI 组件(节点)
    • 1、注册并实现接口
      • 1.1、NativeEntry.h
      • 1.2、NativeEntry.cpp
    • 2、实现 NDK UI 节点
      • 2.1、定义基类 ArkUIBaseNode
      • 2.2、定义UI属性基类
      • 2.3、实现文本节点
      • 2.4、实现列表节点
      • 2.5、实现 CreateTextListExample()
  • 三、使用 NDK UI 组件
    • 1、修改 CMakeLists.txt
    • 2、NativeListPage.ets
    • 3、PC 运行效果
  • 四、总结

〇、前言

如果屏幕前的你经常前往华为鸿蒙开发者官网查询资料,就不难发现最新的开发指南的目录中,ArkUI(方舟UI框架) 一节出现如下图的新变化:
在这里插入图片描述
在此之前,鸿蒙应用的UI 主要用 ArkTS 代码,或者是兼容JS的类 Web 开发,这两种方式,并不支持使用 C++ 代码去实现鸿蒙 UI,也就是说,在之前的原生开发方式中,并不包含 UI 的构建,仅仅只是不涉及用户视图界面的功能性API的封装。

现在,随着鸿蒙生态的逐渐完善,以及 API 的更新迭代,已经支持使用 C++ 代码去构建应用界面,这使得鸿蒙原生开发能力进一步加强,而构建UI的灵活度也进一步得到释放,总的来说,鸿蒙API的这种新特性,是每个想成为优秀的鸿蒙开发工程师的开发者所必需了解和掌握的,刚好,本人最近入手了鸿蒙PC,接下来,就以鸿蒙PC 为适配设备,进行鸿蒙NDK UI 的实践。

一、NDK UI 整体架构

如何创建一个用于原生开发的鸿蒙项目,这里就不进行展开了,因为只需在用 DevEco Studio 创建项目时,选择 Native C++ 项目模板即可:
在这里插入图片描述
NDK UI 的具体运作,离不开 ArkTS 层的配合,具体配合详见下面的架构图:
在这里插入图片描述
与 ArkUI 一样,NDK UI 的实现过程中,也是逐个组件拼装出完整的页面,而每个 NDK UI 组件需要通过接口挂载到UI渲染实例中,并且,NDK UI 组件可以直接挂载到现有的 ArkUI 界面中。

在这里插入图片描述

  • ArkTS声明式UI前端和NDK接口都是针对ArkUI底层实现的接口暴露,NDK接口相比于ArkTS声明式UI前端,除了剥离状态管理等声明式UI语法外,还精简了组件能力,将ArkUI组件核心功能通过C接口进行封装暴露。

  • NDK创建的UI组件需要通过ArkTS层的占位组件进行挂载显示,挂载后,NDK创建的组件和ArkTS创建的组件位于同一个UI树上,相关布局渲染和事件处理遵循相同规则。

二、实现 NDK UI 组件(节点)

下面,开始用 C++ 代码封装一个 NDK UI 组件,也即是用于挂载到 UI 树上的节点,相应的源码文件包含如下:

.
|——cpp
|    |——types
|    |      |——libentry
|    |      |       |——index.d.ts 提供Native和ArkTS侧的桥接方法。
|    |——napi_init.cpp 与index.d.ts对应的桥接方法对接Native侧的定义处。
|    |——NativeEntry.cpp 桥接方法的Native侧实现。
|    |——NativeEntry.h 桥接方法的Native侧定义。
|    |——CMakeList.txt C语言库引用文件。
|    |——ArkUIBaseNode.h 节点封装扩展类。
|    |——ArkUINode.h 节点封装扩展类。
|    |——ArkUIListNode.h 节点封装扩展类。
|    |——ArkUIListItemNode.h 节点封装扩展类。
|    |——ArkUITextNode.h 节点封装扩展类。
|    |——NormalTextListExample.h 示例代码文件。
| 
|——ets
|    |——pages
|         |——Index.ets 应用起始页,用于放置按钮跳转到演示页。
|         |——NativeListPage.ets NDK UI 组件演示页,加载承载Native的容器。
|

1、注册并实现接口

UI 节点,能挂到 UI 树上,就也要能从UI树上摘除,类似于一个文件必然有打开和关闭两种动作,所以,我们需要两个接口去分别实现节点挂载和摘除:

export const createNativeRoot: (content: Object) => void;
export const destroyNativeRoot: () => void;

将上述接口声明代码,添加到 C++ 模块的 src/main/cpp/types/libentry/Index.d.ts 文件中,同时,打开 src/main/cpp/napi_init.cpp 文件,修改 napi_property_descriptor 数组,将上面的新接口关联起来:

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{napi_property_descriptor desc[] = {{ "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr },{"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr},{"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}};napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);return exports;
}
EXTERN_C_END

在 C++ 模块的源码目录 cpp 下面新建一个 NativeEntry.h 和 NativeEntry.cpp 文件:

1.1、NativeEntry.h

/** Copyright (c) 2025 彭友聪* nativePC is licensed under Mulan PSL v2.* You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at:http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  * See the Mulan PSL v2 for more details.  * * Author: 彭友聪 * email:2923616405@qq.com * date: 2025/10/8 08:46* file: ${FILE_NAME}* product: DevEco Studio* LICENSE: MulanPSL-2.0* */
//
// Created on 2025/10/8.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".#ifndef NATIVEPC_NATIVEENTRY_H
#define NATIVEPC_NATIVEENTRY_H
#include "napi/native_api.h"
#include <ArkUIBaseNode.h>
#include <arkui/native_node.h>
#include <arkui/native_type.h>
#include <js_native_api_types.h>namespace NativeModule {
napi_value CreateNativeRoot(napi_env env, napi_callback_info info);
napi_value DestroyNativeRoot(napi_env env, napi_callback_info info);
}class NativeEntry {
private:std::shared_ptr<NativeModule::ArkUIBaseNode> root_;ArkUI_NodeContentHandle handle_;
public:static NativeEntry *GetInstance() {static NativeEntry nativeEntry;return &nativeEntry;}void SetContentHandle(ArkUI_NodeContentHandle handle) {handle_ = handle;}void SetRootNode(const std::shared_ptr<NativeModule::ArkUIBaseNode> &root) {root_ = root;// 添加 Native 组件到 NodeContent 上用于挂载显示OH_ArkUI_NodeContent_AddNode(handle_, root_->GetHandle());}void DisposeRootNode() {OH_ArkUI_NodeContent_RemoveNode(handle_, root_->GetHandle());root_.reset();}
};#endif //NATIVEPC_NATIVEENTRY_H

1.2、NativeEntry.cpp

/** Copyright (c) 2025 彭友聪* nativePC is licensed under Mulan PSL v2.* You can use this software according to the terms and conditions of the Mulan PSL v2.* You may obtain a copy of Mulan PSL v2 at:http://license.coscl.org.cn/MulanPSL2* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.* See the Mulan PSL v2 for more details.** Author: 彭友聪* email:2923616405@qq.com* date: 2025/10/8 09:27* file: ${FILE_NAME}* product: DevEco Studio* LICENSE: MulanPSL-2.0* */
//
// Created on 2025/10/8.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#include "napi/native_api.h"
#include <arkui/native_node_napi.h>
#include <js_native_api.h>
#include "NativeEntry.h"
#include "NormalTextListExample.h"namespace NativeModule {
napi_value CreateNativeRoot(napi_env env, napi_callback_info info) {size_t argc = 1;napi_value args[1] = {nullptr};napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);// 获取 NodeContentArkUI_NodeContentHandle contentHandle;OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);NativeEntry::GetInstance()->SetContentHandle(contentHandle);// 创建文本列表auto list = CreateTextListExample();NativeEntry::GetInstance()->SetRootNode(list);return nullptr;
}napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) {NativeEntry::GetInstance()->DisposeRootNode();return nullptr;
}
}

这里使用到 namespace 关键字,是为了简化方法的引用,不同源码文件下的方法,可以凭借通过命名空间关联起来,具体的,参见后文中的代码。

NativeEntry 类的主要作用就是实现根节点的挂载和摘除,从而起到一个入口作用,有点类似于 ArkTS 代码中的 @Entry 装饰器的功能。

2、实现 NDK UI 节点

在这里,就是一个列表组件,即代码 auto list = CreateTextListExample(); 所引用的具体实现。

不过,在实现 CreateTextListExample() 之前,必须先将对应的组件属性方法实现一下,否则就无法进行样式,如对齐方式、背景色等进行自定义设置。

梳理一下,本文案例所使用到的 NDK UI 节点有:
1)文本节点
2)列表节点
3)列表项节点
这三类节点对应的UI组件,有些属性是共同的,比如宽高,在事件方面也是如此,比如子节点的添加和移除,总之,在具体的编码中,定义一个基类是有必要的。

2.1、定义基类 ArkUIBaseNode

定义一个 ArkUIBaseNode 类,用于实现子节点的管理:

// ArkUIBaseNode.h
#ifndef NATIVEPC_ARKUIBASENODE_H
#define NATIVEPC_ARKUIBASENODE_H#include <arkui/native_type.h>
#include <list>#include "NativeModule.h"namespace NativeModule {
class ArkUIBaseNode {
protected:// 针对父容器子类需要重载下面的函数,实现组件挂载和卸载。virtual void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) {}virtual void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) {}virtual void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) {}ArkUI_NodeHandle handle_;ArkUI_NativeNodeAPI_1 *nativeModule_ = nullptr;private:std::list<std::shared_ptr<ArkUIBaseNode>> children_;public:explicit ArkUIBaseNode(ArkUI_NodeHandle handle): handle_(handle), nativeModule_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()) {}virtual ~ArkUIBaseNode() {// 封装析构函数,实现子节点移除功能if (!children_.empty()) {for (const auto &child : children_) {nativeModule_->removeChild(handle_, child->GetHandle());}children_.clear();}// 封装析构函数,统一回收节点资源nativeModule_->disposeNode(handle_);}void AddChild(const std::shared_ptr<ArkUIBaseNode> &child){children_.emplace_back(child);OnAddChild(child);}void RemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) {children_.remove(child);OnRemoveChild(child);}void InsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) {if (index >= children_.size()) {AddChild(child);} else {auto iter = children_.begin();std::advance(iter, index);children_.insert(iter, child);OnInsertChild(child, index);}}ArkUI_NodeHandle GetHandle() const { return handle_; }
};
} // namespace NativeModule#endif // NATIVEPC_ARKUIBASENODE_H

ArkUIBaseNode 的构造函数所引用的 NativeModuleInstance,是通过如下代码实现的:

//NativeModule.h
#ifndef NATIVEPC_NATIVEMODULE_H
#define NATIVEPC_NATIVEMODULE_H#include <arkui/native_node.h>
#include <cassert>#include <arkui/native_interface.h>namespace NativeModule {
class NativeModuleInstance {
public:static NativeModuleInstance *GetInstance() {static NativeModuleInstance instance;return &instance;}NativeModuleInstance() {// 获取NDK接口的函数指针结构体对象,用于后续操作。OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi_);assert(arkUINativeNodeApi_);}// 暴露给其他模块使用。ArkUI_NativeNodeAPI_1 *GetNativeNodeAPI() { return arkUINativeNodeApi_; }private:ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi_ = nullptr;
};}#endif //NATIVEPC_NATIVEMODULE_H

主要用于获取原生模块示例,从而进行原生模块API的调用。

2.2、定义UI属性基类

通过继承 ArkUIBaseNode 类的方式,再定一个实现公共属性设置方法的属性基类 ArkUINode:

// ArkUINode.h
ifndef NATIVEPC_ARKUINODE_H
#define NATIVEPC_ARKUINODE_H
#include "ArkUIBaseNode.h"
#include "NativeModule.h"
#include <arkui/native_node.h>
#include <arkui/native_type.h>namespace NativeModule { 
class ArkUINode : public ArkUIBaseNode {
protected:// 组件树操作的实现类对接。void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) override {nativeModule_->addChild(handle_, child->GetHandle());}void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) override {nativeModule_->removeChild(handle_, child->GetHandle());}void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) override {nativeModule_->insertChildAt(handle_, child->GetHandle(), index);}public:explicit ArkUINode(ArkUI_NodeHandle handle) : ArkUIBaseNode(handle){}~ArkUINode() override {};// NDK 相关通用属性调用封装void SetWidth(float width) {assert(handle_);ArkUI_NumberValue value[] = {{.f32 = width}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_WIDTH, &item);}void SetPercentWidth(float percent) {assert(handle_);ArkUI_NumberValue value[] = {{.f32 = percent}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_WIDTH_PERCENT, &item);}void SetHeight(float height) {assert(handle_);ArkUI_NumberValue value[] = {{.f32 = height}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_HEIGHT, &item);}void SetPercentHeight(float percent) {assert(handle_);ArkUI_NumberValue value[] = {{.f32 = percent}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_HEIGHT_PERCENT, &item);}void SetBackgroundColor(uint32_t color) {assert(handle_);ArkUI_NumberValue value[] = {{.u32 = color}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item);}void SetItemAlign(ArkUI_ItemAlignment align) {assert(handle_);ArkUI_NumberValue value[] = {{.i32 = align}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_ALIGN_RULES, &item);}void SetListItemAlign(ArkUI_ListItemAlignment align) {assert(handle_);ArkUI_NumberValue value[] = {{.i32 = align}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_LIST_ALIGN_LIST_ITEM, &item);}
};
}#endif //NATIVEPC_ARKUINODE_H

2.3、实现文本节点

用于演示的 NDK UI 组件——list 组件,列表项中用到了文本,所以,需要一个文本节点去展示对应文本:

//ArkUITextNode.h
#ifndef NATIVEPC_ARKUITEXTNODE_H
#define NATIVEPC_ARKUITEXTNODE_H
#include "ArkUINode.h"#include <string>namespace NativeModule { 
class ArkUITextNode : public ArkUINode {
public:ArkUITextNode(): ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_TEXT)) {}// 文本属性NDK接口封装。void SetFontSize(float fontSize) {assert(handle_);ArkUI_NumberValue value[] = {{.f32 = fontSize}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_FONT_SIZE, &item);}void SetFontColor(uint32_t color) {assert(handle_);ArkUI_NumberValue value[] = {{.u32 = color}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_FONT_COLOR, &item);}void SetTextContent(const std::string &content) {assert(handle_);ArkUI_AttributeItem item = {nullptr, 0, content.c_str()};nativeModule_->setAttribute(handle_, NODE_TEXT_CONTENT, &item);}void SetTextAlign(ArkUI_TextAlignment align) {assert(handle_);ArkUI_NumberValue value[] = {{.i32 = align}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_TEXT_ALIGN, &item);}
};
}#endif //NATIVEPC_ARKUITEXTNODE_H

2.4、实现列表节点

这里为了体现父子节点的关系,实现了一个列表节点:

//ArkUIListNode.h
#ifndef NATIVEPC_ARKUILISTNODE_H
#define NATIVEPC_ARKUILISTNODE_H
#include "ArkUINode.h"namespace NativeModule { 
class ArkUIListNode : public ArkUINode {
public:ArkUIListNode(): ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST)) {}  // 创建ArkUI的列表组件。// List 组件的属性NDK接口封装void SetScrollBarState(bool isShow) {assert(handle_);ArkUI_ScrollBarDisplayMode displayMode =isShow ? ARKUI_SCROLL_BAR_DISPLAY_MODE_ON : ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF;ArkUI_NumberValue value[] = {{.i32 = displayMode}};ArkUI_AttributeItem item = {value, 1};nativeModule_->setAttribute(handle_, NODE_SCROLL_BAR_DISPLAY_MODE, &item);}
};
}#endif //NATIVEPC_ARKUILISTNODE_H

列表的内容是通过其子组件列表项进行体现的,所以,定义列表节点就必须相应的定义列表项节点:

//ArkUIListItemNode.h
#ifndef NATIVEPC_ARKUILISTITEMNODE_H
#define NATIVEPC_ARKUILISTITEMNODE_H
#include "ArkUINode.h"namespace NativeModule { 
class ArkUIListItemNode: public ArkUINode {
public:ArkUIListItemNode(): ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM)) {}
};
}#endif //NATIVEPC_ARKUILISTITEMNODE_H

从上面的代码可以看到,文本节点、列表节点以及列表项节点,都是直接继承 ArkUINode 类,从而间接继承 ArkUIBaseNode 类。

2.5、实现 CreateTextListExample()

CreateTextListExample() 依赖代码都准备好之后,便可以开始它本身的实现代码的编辑了:

// NormalTextListExample.h
#ifndef NATIVEPC_NORMALTEXTLISTEXAMPLE_H
#define NATIVEPC_NORMALTEXTLISTEXAMPLE_H
#include "ArkUIBaseNode.h"
#include "ArkUIListItemNode.h"
#include "ArkUIListNode.h"
#include "ArkUITextNode.h"namespace NativeModule {std::shared_ptr<ArkUIBaseNode> CreateTextListExample() {// 创建组件并挂载// 1:使用智能指针创建List组件。auto list = std::make_shared<ArkUIListNode>();list->SetPercentWidth(1);list->SetPercentHeight(1);list->SetScrollBarState(true);list->SetItemAlign(ARKUI_ITEM_ALIGNMENT_CENTER);list->SetListItemAlign(ARKUI_LIST_ITEM_ALIGNMENT_CENTER);// 2:创建ListItem子组件并挂载到List上。for (int32_t i = 0; i < 30; ++i) {auto listItem = std::make_shared<ArkUIListItemNode>();auto textNode = std::make_shared<ArkUITextNode>();textNode->SetTextContent(std::to_string(i));textNode->SetFontSize(16);textNode->SetFontColor(0xFFff00ff);textNode->SetPercentWidth(1);textNode->SetWidth(300);textNode->SetHeight(100);textNode->SetBackgroundColor(0xFFfffacd);textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER);listItem->InsertChild(textNode, i);list->AddChild(listItem);}return list;
}
}#endif //NATIVEPC_NORMALTEXTLISTEXAMPLE_H

三、使用 NDK UI 组件

1、修改 CMakeLists.txt

在开始使用 NDK UI 组件之前,有个收尾工作必须完成的就是修改 CMakeLists.txt 文件:

# the minimum version of CMake.
cmake_minimum_required(VERSION 3.5.0)
project(nativePC)set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})if(DEFINED PACKAGE_FIND_FILE)include(${PACKAGE_FIND_FILE})
endif()include_directories(${NATIVERENDER_ROOT_PATH}${NATIVERENDER_ROOT_PATH}/include)add_library(entry SHARED napi_init.cpp NativeEntry.h NativeEntry.cpp ArkUIBaseNode.h NativeModule.h NormalTextListExample.h ArkUINode.h ArkUIListNode.h ArkUIListItemNode.h ArkUITextNode.h)
target_link_libraries(entry PUBLIC libace_napi.z.so libace_ndk.z.so)

必须提醒的是,libace_ndk.z.so 一定不要忘记加上,否则就会报很多 undefined symbol,如 d.lld: error: undefined symbol: OH_ArkUI_NodeContent_AddNode

2、NativeListPage.ets

src/main/ets/pages/ 目录下创建一个名称如是的文件,并编辑如下内容:

import nativeNode from 'libentry.so'
import { NodeContent, router } from '@kit.ArkUI'@Entry
@Component
struct NativeListPage {// 初始化 NodeContent 对象private rootSlot = new NodeContent();@State @Watch('changeNativeFlag') showNative: boolean = false;changeNativeFlag() {if(this.showNative) {// 传递 NodeContent 对象用于 Native 创建组件的挂载显示nativeNode.createNativeRoot(this.rootSlot)} else {// 销毁 NativeModule 组件nativeNode.destroyNativeRoot()}}build() {Column({space: 15}){Button("Back").height(80).width("30%").backgroundColor(Color.Black).fontColor(Color.White).onClick(() => {router.back()})Button(this.showNative ? "HideNativeUI" : "showNativeUI").height(80).width("30%").backgroundColor(Color.Black).fontColor(Color.White).onClick(() => {this.showNative = !this.showNative;})Row() {ContentSlot(this.rootSlot)}.width("100%").height("70%").alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center)}.width("100%").height("100%").alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)}
}

其中,比较关键的代码是:
1)private rootSlot = new NodeContent();
2)ContentSlot(this.rootSlot)

ContentSlot 是专门用于渲染并管理Native层使用C-API创建的组件。
在这里插入图片描述
下一步,是将这个演示页的路由注册一下,就是在 src/main/resources/base/profile/main_pages.json 添加上 "pages/NativeListPage",这个路由就可以在 Index.ets 即应用入口页的跳转按钮中使用:

import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';
import { router } from '@kit.ArkUI';const DOMAIN = 0x0000;@Entry
@Component
struct Index {@State message: string = 'Hello World';build() {Row() {Column({ space: 15 }) {Text(this.message).fontSize($r('app.float.page_text_font_size')).fontWeight(FontWeight.Bold).onClick(() => {this.message = 'Welcome';hilog.info(DOMAIN, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.add(2, 3));})Button("NativeListPage").height(80).width("30%").backgroundColor(Color.Black).fontColor(Color.White).onClick(() => {router.push({ url: 'pages/NativeListPage' });})}.width('100%')}.height('100%')}
}

3、PC 运行效果

在这里插入图片描述
最终,部署到鸿蒙PC上的运行效果如上。

四、总结

本文主要介绍如何实现 NDK UI 并进行使用,NDK UI 是近期推出的鸿蒙 API 特性,旨在进一步强化鸿蒙平台的原生开发能力,提高UI实现的灵活度,详细阅读本文将对你的鸿蒙开发能力形成助力。

http://www.dtcms.com/a/457064.html

相关文章:

  • gRPC从0到1系列【25】
  • 冠县网站建设电话wordpress优化打开速度插件
  • Redis中string底层实现原理
  • 百度经验官方网站登录入口常州网站建设方案优化
  • 网站改域名如何做百度优化企业网站营销典型案例
  • Java采用easyexcel组件进行excel表格单元格的自动合并
  • 整体设计 逻辑系统程序 之18 Source 容器(Docker)承载 C/P/D 三式的完整设计与双闭环验证 之2
  • 汽车保险网站简历模板大学生
  • 基于pytest的接口测试
  • 阿里巴巴做网站需要多少钱镇江vi设计
  • 嵌入式Linux(以泰山派无 eMMC 版为例,嘉立创给的Linux镜像有问题!)系统报错磁盘不够但我用的是32G不可能不够怎么解决
  • 开源一个本地AI知识库
  • js哈哈哈哈哈哈哈哈哈哈
  • 做外汇都要看什么网站多元网站建设
  • 一些主要应用和NAT
  • AI编程开发系统028-基于Vue+SpringBoot的宠物领养系统系统(源码+部署说明+演示视频+PPT+lw)
  • MySQL连接池原理与网站数据流动(了解)
  • Hadess入门到实战(8) - 如何管理Go制品
  • 最短路径问题总结
  • 建设银行网站为什么登不上门头设计
  • NX543NX551美光SSD固态闪存NX552NX564
  • 倍增:快速幂
  • 网站关键词快速排名工具网站建设项目可行性分析
  • 开源AI智能名片链动2+1模式S2B2C商城小程序在现代营销运营中的应用与实践
  • 自然语言处理分享系列-词向量空间中的高效表示估计(二)
  • 开发Bug——U盘插入断网
  • 开源 C++ QT QML 开发(十)通讯--串口
  • BMS(电池管理系统)的主要功能和架构简述
  • asp业务网站视频链接生成器
  • Flask模板中使用React、ant-design、@ant-design/icons示例模板