鸿蒙开发入门day19-使用NDK接口构建UI(一)

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,还请三连支持一波哇ヾ(@^∇^@)ノ)

目录

NDK接口概述

整体架构

开发流程

接入ArkTS页面

占位组件

NDK组件模块

示例


 

NDK接口概述

ArkUI开发框架提供了一系列NDK接口,能够在应用中使用C和C++代码构建UI界面,这些接口包括UI组件创建、UI树操作、属性设置和事件监听等。面向通用UI界面开发场景,建议使用ArkTS代码和ArkUI声明式开发框架。然而,如果需要实现以下一个或多个目标,那么ArkUI NDK接口就能派上用场:

  • 需要使用UI组件树控制接口来动态创建和挂载UI组件,方便实现自身UI开发框架的系统桥接。

  • 进一步提升UI界面性能,细粒度控制组件的创建和属性设置,以降低延迟、处理极高UI负载。

  • 重复使用自己或其他开发者的C或C++UI库。

ArkUI NDK接口能力主要包括:

  • 布局

    布局是UI的必要元素,定义了组件在界面中的大小位置。ArkUI NDK接口提供了线性布局、层叠布局、弹性布局、相对布局、滚动容器、轮播容器等。

  • 组件

    组件是UI的必要元素,形成了在界面中的样子。包括系统内置组件和用户自定义布局绘制行为的组件。系统内置组件包括按钮、单选框、图片、文本等,可以使用ArkUI NDK提供的接口快速创建相应组件并设置属性和事件。针对UI组件的自定义能力包括了布局测算和绘制,用户可以通过这些自定义能力构建差异化UI组件。

  • 弹窗

    弹窗是UI界面交互的重要元素。ArkUI NDK接口提供了自定义弹窗相关接口,可以自定义弹窗界面内容并调用相关弹窗接口展示弹窗。

  • 动画

    动画是UI的重要元素之一。优秀的动画设计能够极大地提升用户体验,ArkUI NDK提供了显式动画接口用于快速构建组件的属性动画、实现高效精致的动画效果。

  • 交互事件

    交互事件是UI和用户交互的必要元素。ArkUI NDK接口提供了多种交互事件,除了触摸事件、鼠标事件、焦点事件等通用事件外,还包括基于通用事件进行进一步识别的手势事件。手势事件有单一手势如点击手势、长按手势、拖动手势、捏合手势、旋转手势、滑动手势,以及通过单一手势事件进行组合的组合手势事件。

整体架构

图1 NDK接口和ArkTS声明式关系架构图

图2 通过NDK接口创建的组件挂载示意图

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

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

开发流程

使用NDK接口开发UI界面时,主要涉及如下开发过程。

任务简介
NDK开发导读介绍NDK的适用场景与必备基础知识。
接入ArkTS页面介绍了如何将NDK接口开发的UI界面挂载到ArkTS主页面上进行渲染显示。
监听组件事件介绍了如何注册组件的事件监听和添加手势交互。
使用动画介绍了如何在Native侧添加动画。
使用懒加载开发长列表界面介绍了如何使用懒加载能力在Native侧开发高性能长列表界面。
构建弹窗介绍了如何使用弹窗接口构建UI界面进行弹窗显示。
构建自定义组件介绍了如何使用NDK接口能力构建自定义组件,实现差异化UI组件。
嵌入ArkTS组件介绍了如何在Native侧构建带有ArkTS组件的界面。

接入ArkTS页面

占位组件

使用NDK接口构建UI界面时,需要在ArkTS页面创建用于挂载NDK接口创建组件的占位组件。占位组件类型为ContentSlot,ContentSlot能够绑定一个NodeContent对象,该对象可通过Node-API传递到Native侧挂载显示Native组件。

占位组件和其他ArkTS内置组件使用方法相同。

import { NodeContent } from '@kit.ArkUI';@Entry
@Component
struct Index {// 初始化NodeContent对象。private rootSlot = new NodeContent();@State @Watch('changeNativeFlag') showNative: boolean = false;changeNativeFlag(): void {if (this.showNative) {// 传递NodeContent对象用于Native创建组件的挂载显示nativeNode.createNativeRoot(this.rootSlot)} else {// 销毁NativeModule组件nativeNode.destroyNativeRoot()}}build() {Column() {Button(this.showNative ? "HideNativeUI" : "ShowNativeUI").onClick(() => {this.showNative = !this.showNative})Row() {// 将NodeContent和ContentSlot占位组件绑定。ContentSlot(this.rootSlot)}.layoutWeight(1)}.width('100%').height('100%')}
}

占位组件可以通过相关接口在Native侧转化为挂载对象。

ArkUI_NodeContentHandle contentHandle;
OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);

挂载对象提供了相关挂载和卸载组件接口。

OH_ArkUI_NodeContent_AddNode(handle_, myNativeNode);
OH_ArkUI_NodeContent_RemoveNode(handle_, myNativeNode);

NDK组件模块

NDK提供的UI组件能力如组件创建、树操作、属性设置、事件注册等是通过函数指针结构体(如ArkUI_NativeNodeAPI_1)进行暴露,该函数指针结构体可以通过模块查询接口获取。

ArkUI_NativeNodeAPI_1* arkUINativeNodeApi = nullptr;
OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi);

在获取到函数指针结构体后,可以使用该结构体内的函数实现相关UI组件操作。

组件创建和销毁。

auto listNode = arkUINativeNodeApi->createNode(ARKUI_NODE_LIST);
arkUINativeNodeApi->disposeNode(listNode);

组件树操作。

auto parent = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK);
auto child = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK);
arkUINativeNodeApi->addChild(parent, child);
arkUINativeNodeApi->removeChild(parent, child);

属性设置。

auto stack = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK);
ArkUI_NumberValue value[] = {{.f32 = 100}};
ArkUI_AttributeItem item = {value, 1};
arkUINativeNodeApi->setAttribute(stack, NODE_WIDTH, &item);
ArkUI_NumberValue value[] = {{.u32 = 0xff112233}};
ArkUI_AttributeItem item = {value, 1};
arkUINativeNodeApi->setAttribute(stack, NODE_BACKGROUND_COLOR, &item);

事件注册。

auto stack = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK);
arkUINativeNodeApi->addNodeEventReceiver(stack, [](ArkUI_NodeEvent* event){// process event
});
arkUINativeNodeApi->registerNodeEvent(stack, NODE_ON_CLICK, 0, nullptr);

示例

下面的示例展示了如何使用ContentSlot挂载Native侧的文本列表。

图1 Native文本列表

1.在ArkTS页面上声明用于Native页面挂载的占位组件,并在页面创建时通知Native侧创建文本列表。

import nativeNode from 'libentry.so';
import { NodeContent } from '@kit.ArkUI';@Entry
@Component
struct Index {// 初始化NodeContent对象。private rootSlot = new NodeContent();@State @Watch('changeNativeFlag') showNative: boolean = false;changeNativeFlag(): void {if (this.showNative) {// 传递NodeContent对象用于Native创建组件的挂载显示nativeNode.createNativeRoot(this.rootSlot)} else {// 销毁NativeModule组件nativeNode.destroyNativeRoot()}}build() {Column() {Button(this.showNative ? "HideNativeUI" : "ShowNativeUI").onClick(() => {this.showNative = !this.showNative})Row() {// 将NodeContent和ContentSlot占位组件绑定。ContentSlot(this.rootSlot)}.layoutWeight(1)}.width('100%').height('100%')}
}

2.使用Native模板创建工程,并在Native侧提供Node-API的桥接方法,实现ArkTS侧的NativeNode模块接口。

接口声明。

// entry/src/main/cpp/types/libentry/Index.d.tsexport const createNativeRoot: (content: Object) => void;
export const destroyNativeRoot: () => void;

Native实现。

// entry/src/main/cpp/napi_init.cpp#include "NativeEntry.h"
#include "napi/native_api.h"EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {// 绑定Native侧的创建组件和销毁组件。napi_property_descriptor desc[] = {{"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_ENDstatic napi_module demoModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = Init,.nm_modname = "entry",.nm_priv = ((void *)0),.reserved = {0},
};extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }

3.在NativeEntry.h文件中创建Native界面。

// NativeEntry.h#ifndef MYAPPLICATION_NATIVEENTRY_H
#define MYAPPLICATION_NATIVEENTRY_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);// 管理Native组件的生命周期和内存。
class NativeEntry {
public:static NativeEntry *GetInstance() {static NativeEntry nativeEntry;return &nativeEntry;}void SetContentHandle(ArkUI_NodeContentHandle handle) {handle_ = handle;}void SetRootNode(const std::shared_ptr<ArkUIBaseNode> &baseNode) {root_ = baseNode;// 添加Native组件到NodeContent上用于挂载显示。OH_ArkUI_NodeContent_AddNode(handle_, root_->GetHandle());}void DisposeRootNode() {// 从NodeContent上卸载组件并销毁Native组件。OH_ArkUI_NodeContent_RemoveNode(handle_, root_->GetHandle());root_.reset();}private:std::shared_ptr<ArkUIBaseNode> root_;ArkUI_NodeContentHandle handle_;
};} // namespace NativeModule#endif // MYAPPLICATION_NATIVEENTRY_H

对应实现文件。

// NativeEntry.cpp
#include "NativeEntry.h"#include <arkui/native_node_napi.h>
#include <hilog/log.h>
#include <js_native_api.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();// 保持Native侧对象到管理类中,维护生命周期。NativeEntry::GetInstance()->SetRootNode(list);return nullptr;
}napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) {// 从管理类中释放Native侧对象。NativeEntry::GetInstance()->DisposeRootNode();return nullptr;
}} // namespace NativeModule

【ACM出版,快至2个月EI检索】第二届物联网与云计算技术国际学术会议 (IoTCCT 2024)_艾思科蓝_学术一站式服务平台

更多学术会议请看 学术会议-学术交流征稿-学术会议在线-艾思科蓝

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/53946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

unity3d入门教程六

unity3d入门教程六 15.1预制体15.2编辑预制体15.3在场景中编辑15.4动态创建实例15.5实例的销毁16.1&#xff08;练习&#xff09;子弹发射16.2定时器16.3键盘事件 15.1预制体 火神山10天建成&#xff0c;使用了预制体技术 一个个小房间都是事先建造好的&#xff0c;最后吊车装…

ICPC网络赛 以及ACM训练总结

一、训练反思 关于我自己暑假期间训练的反思&#xff0c;我承认无论是因为什么原因&#xff0c;我自己浪费我整整一个暑假的时间&#xff0c;暑假期间正是我们集训的关键时期&#xff0c;这期间没有任何的事情来打扰我们学习&#xff0c;而我却熬夜&#xff0c;白天训练懈怠&a…

在服务器上开Juypter Lab教程(远程访问)

在服务器上开Juypter Lab教程&#xff08;远程访问&#xff09; 文章目录 在服务器上开Juypter Lab教程&#xff08;远程访问&#xff09;一、安装anaconda1、安装anaconda2、提权限3、运行4、同意协议5、安装6、是否要自动初始化 conda7、结束8、检查 二、Anaconda安装Pytorch…

python 自动化测试接口

比如我们要测试接口&#xff1a;identity/chatRecords/pages 已在Postman中有&#xff0c;那我们就可以直接从里面复制出Python脚本 新建&#xff1a; pagerequest.py import requests import jsonurl "http://192.168.31.132:70/identity/chatRecords/pages"payl…

基于AgentUniverse在金融场景中的多智能体应用探索

基于AgentUniverse在金融场景中的多智能体应用探索 1.基于大模型智能体超级状态机 智能体、多智能体都是当下的技术热点,但作为一个技术人应该理解,所有的技术都有自己所针对的问题、及其能力边界,并不存在普适的、放诸业务场景皆 work 的技术方案。在这里尝试区分,从大模…

[数据集][目标检测]高铁受电弓检测数据集VOC+YOLO格式1245张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1245 标注数量(xml文件个数)&#xff1a;1245 标注数量(txt文件个数)&#xff1a;1245 标注…

2024年华为9月4日秋招笔试真题题解

2024年华为0904秋招笔试真题 二叉树消消乐好友推荐系统维修工力扣上类似的题--K站中转内最便宜的航班 二叉树消消乐 题目描述 给定原始二叉树和参照二叉树(输入的二叉树均为满二叉树&#xff0c;二叉树节点的值范围为[1,1000]&#xff0c;二叉树的深度不超过1000)&#xff0c…

线性表之单链表

在上一节我们学习了线性表中的顺序表&#xff0c;今天我们来学习一下线性表中的另一种结构——单链表 前言 我们在之前已经初步了解了数据结构中的两种逻辑结构&#xff0c;但线性结构中并非只有顺序表一种&#xff0c;它还有不少兄弟姐妹&#xff0c;今天我们再来学习一下单链…

Python基础语法(3)下

列表和元组 列表是什么&#xff0c;元组是什么 编程中&#xff0c;经常需要使用变量&#xff0c;来保存/表示数据。变量就是内存空间&#xff0c;用来表示或者存储数据。 如果代码中需要表示的数据个数比较少&#xff0c;我们直接创建多个变量即可。 num1 10 num2 20 num3…

[数据集][目标检测]葡萄成熟度检测数据集VOC+YOLO格式1123张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1123 标注数量(xml文件个数)&#xff1a;1123 标注数量(txt文件个数)&#xff1a;1123 标注…

【重学 MySQL】二十九、函数的理解

【重学 MySQL】二十九、函数的理解 什么是函数不同 DBMS 函数的差异函数名称和参数功能实现数据类型支持性能和优化兼容性和可移植性 MySQL 的内置函数及分类单行函数多行函数&#xff08;聚合函数&#xff09;使用注意事项 什么是函数 函数&#xff08;Function&#xff09;在…

秋韵虫趣.

文章目录 虫鸣概览虫坛文化蟀种纷呈中华蟋蟀宁阳蟋蟀刻点铁蟋长颚斗蟋 油葫芦棺头蟋中华灶蟋小素蟋树皮蟋蟀 花生大蟋斑腿针蟋其他鸣虫树蟋&#xff0c;又名竹蛉、邯郸梨片蟋&#xff0c;又名金钟、天蛉、绿蛣蛉、银琵琶凯纳奥蟋&#xff0c;又名石蛉&#xff0c;鳞蟋黄蛉蟋&am…

Python | Leetcode Python题解之第409题最长回文串

题目&#xff1a; 题解&#xff1a; class Solution:def longestPalindrome(self, s: str) -> int:ans 0count collections.Counter(s)for v in count.values():ans v // 2 * 2if ans % 2 0 and v % 2 1:ans 1return ans

本地部署大模型并使用知识库Windows下Ollama+Docker+MaxKB安装的记录

概要 本文介绍本地部署大模型和知识库的小白方法&#xff0c;可以运行较多种类的大模型&#xff0c;使用的软件为docker和ollama以及MaxKb作为知识库前端。 下载 各安装包可以百度去官网或者github下载或使用&#xff0c;也可以点击下面的的链接和我下载相同的版本。 ollama…

Lnux-gcc/g++使用

目录 1.gcc/g介绍 1.什么是 gcc / g 2.gcc/g指令格式 2. gcc / g 实现程序翻译的过程 1.预处理(进行宏替换) 2.编译(生成汇编&#xff09; 3.汇编&#xff08;生成机器可识别代码&#xff09; 4.连接&#xff08;生成可执行文件或库文件&#xff09; 1.gcc/g介绍 1.什么…

小明震惊OpenAI 的新模型 01

在硅谷的中心&#xff0c;繁忙的咖啡馆和创业中心周围&#xff0c;年轻的软件工程师小明坐在他的办公桌前&#xff0c;面露困惑。科技界一直在盛传一项新的AI突破&#xff0c;但他持怀疑态度&#xff0c;不敢抱太大希望。他认为AI泡沫即将破灭&#xff0c;炒作列车即将出轨&…

【计算机网络】网络通信中的端口号

文章目录 一、引入端口号二、端口号的作用三、端口号的确定 在TCP/IP协议中&#xff0c;传输层有两个重要的协议&#xff1a;TCP&#xff08;传输控制协议&#xff09;和UDP&#xff08;用户数据报协议&#xff09;。TCP用于提供可靠的数据传输&#xff0c;而UDP则适合用于广播…

电子电气架构 --- 基于ISO 26262的车载电子软件开发流程

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…

《ImageNet Classification with Deep Convolutional Neural Networks》论文导读

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl《ImageNet Classification with Deep Convolutional Neural Networks》是一篇在深度学习领域具有重要影响力的论文,由Alex Krizhevsky、Ilya Sutskever和Geoffrey E. Hinton等人撰写。该论文主要…

golang实现正向代理http_proxy和https_proxy

package mainimport ("bytes""fmt""io""log""net""net/url""strings" )func main() {// tcp 连接&#xff0c;监听 8080 端口l, err : net.Listen("tcp", ":8080")if err ! nil {l…