UIKit 入门与 UIView 基础
本文档用于在 HiDiTing V100 上开发基于 UIKit 的 C++ 图形界面。文档先说明图形子系统、组件关系和真实应用页面的实现流程,再保留各类组件、资源、表盘、旋转和 DFX 的详细说明,供开发者按需查阅。
UIKit 背景知识
图形子系统与组件关系
UIKit是基于轻量OS构建的图形子系统,满足硬件资源较小的物联网设备的系统应用开发,其核心模块如图1所示。

-
各模块介绍
- Component:应用组件,包括UIView、UIViewGroup、UIButton、UILabel、UILabelButton、UIList、UISlider等。
- Animator:动画模块,开发者可以自定义动画。
- Layout:布局控件,包括Flexlayout、GridLayout、ListLayout等。
- Transform:图形变换模块,包括旋转、平移、缩放等。
- DFX:维测模块。
- Font:字体模块,包括字库管理及多语言切换等。
- ImageCache:图片缓存模块,包括图片加载和释放功能以及LRU自动回收机制等。
- Event:事件模块,包括click、press、drag、long press等基础事件。
- Render Engine:渲染绘制模块。
- Gralloc Engine:图形内存管理模块。
- Display Device:图形显示管理模块。
- Input Device:输入设备管理模块。
- Display Vau:图形硬件渲染适配层。
- Display Gralloc:图形内存管理适配层。
- Display Layer:图层管理适配层。
- Input Manager:输入设备管理适配层。
-
目录
快速跑通 UIKit Demo
功能说明
本节使用 SDK 已有的 HelloWorld 页面作为最小 UIKit 场景。该页面已纳入 diting-community 的 nativelauncher 组件:HelloWorldPresenter.cpp 通过 REGIST_MENU 注册应用菜单,HelloWorldPage.cpp 通过 REGIST_SLICE_PAGE 注册页面;进入页面时创建容器和标签并显示 Hello World。

准备工作
说明:本文示例命令以一站式 CLI 为主。实际开发可从以下三种环境中选择,推荐使用一站式 CLI。
| 开发环境 | 适用场景 | 使用指南 |
|---|---|---|
| 一站式 CLI(推荐) | 快速完成目标选择、构建、烧录和串口监视 | 一站式 CLI 开发环境使用指南 |
| HiSpark Studio for VS Code | 图形化编辑、编译、烧录和调试 | HiSpark Studio for VS Code 开发环境使用指南 |
| WSL 与 Docker | 在 Windows 上使用一致的 Linux 容器构建环境 | WSL 与 Docker 环境使用指南 |
按 一站式 CLI 开发环境使用指南 准备环境、构建和烧录;构建前确保 fbb doctor 成功。
3322 diting-community 的目标配置已经启用 SDK_DITING_COMMUNITY、SUPPORT_OHOSFWK、ENABLE_UIKIT 和 CONFIG_NATIVEAPP_TEST。相关定义位于 /src/build/config/target_config/3322/config.py,无需为本示例额外打开 UIKit 组件。
使用方式
构建并烧录默认 diting-community 固件后,打开设备应用菜单,选择 HelloWorld。页面应显示居中的 Hello World 文本;返回或退出页面后,页面析构函数会释放容器、标签和该页面加载的图片资源。
涉及接口
| 接口或类 | 用途 | 参考 |
|---|---|---|
UIViewGroup |
页面内的容器,管理子视图 | Add、RemoveAll |
UILabel |
显示文本 | SetText、SetAlign、SetFont |
UIView |
所有组件的基类,提供位置与尺寸控制和事件属性 | SetPosition(位置和尺寸)、SetDraggable、SetTouchable |
ImageCacheManager |
加载和释放多分辨率图片资源 | LoadAllInMultiRes(文件)、UnloadAllInMultiRes(文件) |
| Native 页面框架 | 将 UIKit 页面接入 Native 应用框架 | AddViewToPageContainer、REGIST_SLICE_PAGE、REGIST_MENU |
预期结果
- 应用菜单中出现
HelloWorld。 - 进入后显示
Hello World标签,文本使用默认矢量字体并水平、垂直居中。 - 页面退出后没有重复加载资源、悬空视图或重复注册页面的日志。
文件结构与代码走读
| 文件 | 作用 |
|---|---|
| /src/application/wearable/nativeapp/nativeui/helloworldpage/HelloWorldPresenter.cpp | 用 REGIST_MENU 向应用菜单注册 HelloWorld |
| /src/application/wearable/nativeapp/nativeui/helloworldpage/HelloWorldPage.cpp | 注册页面、创建组件、加载资源和释放资源 |
| /src/application/wearable/nativeapp/nativeui/include/helloworldpage/HelloWorldPage.h | 页面类声明和组件成员所有权 |
| /src/application/wearable/nativeapp/nativelauncher/include/AppViewIDs.h | 应用视图 ID 枚举,包含 VIEW_HELLOWORLD |
| /src/application/wearable/nativeapp/CMakeLists.txt | 递归收集 nativeui/*.cpp 并构建 nativelauncher |
HelloWorldPresenter.cpp 的核心是:
REGIST_MENU(VIEW_HELLOWORLD, HelloWorldView, HelloWorldPresenter,
EMPTY_ICON, EMPTY_ICON, "HelloWorld");
该注册使启动框架能够在应用菜单中找到对应 View、Presenter 和标题,宏定义见 REGIST_MENU。HelloWorldPage.cpp 再将视图 ID、页 ID 和页面类关联:
HelloWorldPage::OnStart() 是实际绘制流程:先使用 ImageCacheManager::LoadAllInMultiRes() 加载页面资源;随后创建 UIViewGroup 和 UILabel,调用 SetPosition()、SetDraggable()、SetTouchable()、SetAlign()、SetFont() 和 SetText() 设置标签,最后执行 UIViewGroup::Add() 与 AddViewToPageContainer()。析构函数按相反方向 RemoveAll()、删除对象、UnloadAllInMultiRes(),避免页面切换后资源泄漏。REGIST_SLICE_PAGE 的定义见 /src/application/wearable/nativeabilityfwk/include/SlicePageFactory.h。
基于 UIKit Demo 开发自己的应用
新建页面
- 在 /src/application/wearable/nativeapp/nativeui 下新建页面源文件目录,并在
nativeui/include下新建对应头文件目录。 - 在 /src/application/wearable/nativeapp/nativelauncher/include/AppViewIDs.h 中增加唯一的
VIEW_MY_APP枚举值。 - 仿照 HelloWorld 创建
MyAppView、MyAppPresenter和继承SlicePage<MyAppPresenter>的MyAppPage;在 Presenter 中注册菜单,在页面源文件中注册首页面。 - 在
OnStart()中创建组件树;在析构函数或页面退出回调中按创建的反向顺序移除视图、释放资源。
REGIST_MENU(VIEW_MY_APP, MyAppView, MyAppPresenter,
EMPTY_ICON, EMPTY_ICON, "MyApp");
REGIST_SLICE_PAGE(VIEW_MY_APP, 1, MyAppPage, true);
关键代码片段
void MyAppPage::OnStart(void *data)
{
auto *container = new UIViewGroup();
container->SetPosition(0, 0, HORIZONTAL_RESOLUTION, VERTICAL_RESOLUTION);
auto *label = new UILabel();
label->SetPosition(20, 120, 360, 48);
label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
label->SetText("My UIKit App");
container->Add(label);
AddViewToPageContainer(container);
}
示例仅展示组件树构建顺序。实际页面必须保存 container、label 的成员指针,并在析构时先从容器移除子视图,再释放对象;涉及图片时,同时配对调用资源加载和卸载接口。
构建与验证
nativelauncher 的 CMake 已递归收集 nativeui/*.cpp,因此新增页面源文件无需单独添加 CMake 源文件列表;但新增头文件路径应遵循现有 nativeui/include 组织。重新配置并构建固件后,在应用菜单确认 MyApp 出现,进入后检查组件显示、按键/触摸响应和退出后的资源释放。
UIKit 组件与功能详细说明
API Reference 入口
下文保留各组件的功能、参数和效果说明。需要查阅完整声明、继承关系和单个接口约束时,可按组件类别进入 API Reference;组件表中的函数名应以这些接口声明和对应 SDK 头文件为准。
| 组件类别 | 主要用途 | API Reference |
|---|---|---|
| 视图树与事件 | UIView、UIViewGroup、RootView,用于布局、容器管理和输入事件分发 |
UIView、UIViewGroup、RootView |
| 布局与滚动容器 | Grid/Flex/List 布局,滚动、滑动和列表场景 | 布局、UIList、UIScrollView |
| 文本、按钮和图片 | 标签、按钮、图片显示和交互 | UILabel、UIButton、UIImageView |
| 绘制与资源 | Canvas 绘制、字体和图片缓存 | UICanvas、字体管理、ImageCacheManager |
| 动画、DFX 与服务 | 动画、帧率/截图/控件树和 Graphic Service | Animator、DFX 命令、Graphic Service |
组件继承关系
所有组件均继承于UIView,组件分为基础组件和容器组件。
- 基础组件仅实现组件本身单一功能,例如UIButton、UILabel、UIImageView等。
- 容器类组件可以添加其他组件作为自身的子组件,例如RootView、UIList、UIPicker等。
本章主要介绍各个组件的使用,并以sample的形式呈现,指导用户开发。

UIView和UIViewGroup
UIView为所有组件的父类,所有组件都继承自UIView,实现自定义扩展。例如UIViewGroup继承于UIView,并扩展其容器特性(允许添加其他组件)。
下面分别介绍了UIView和UIViewGroup的常用函数,同时也是所有派生组件的公共函数。
UIView函数介绍
UIView常用函数如表1所示,用户可以结合实际情况使用。
表 1 UIView常用函数说明
表 2 AlignmentType说明
枚举值 |
介绍 |
|---|---|
ALIGN_DEFAULT |
默认值,不对齐 |
ALIGN_TOP_LEFT |
控件左上角对齐到父容器内容区左上角 |
ALIGN_TOP_MID |
控件顶部中点对齐到父容器内容区顶部中点 |
ALIGN_TOP_RIGHT |
控件右上角对齐到父容器内容区右上角 |
ALIGN_MID_LEFT |
控件右下角对齐到父容器内容区右下角 |
ALIGN_MID_MID |
控件右边缘中点对齐到父容器内容区右边缘中点 |
ALIGN_MID_RIGHT |
控件中心对齐到父容器内容区中心 |
ALIGN_BOTTOM_LEFT |
控件左下角对齐到父容器内容区左下角 |
ALIGN_BOTTOM_MID |
控件底部中点对齐到父容器内容区底部中点 |
ALIGN_BOTTOM_RIGHT |
控件右下角对齐到父容器内容区右下角 |
ALIGN_OUT_TOP_LEFT |
控件左下角对齐到参考对象左上角 |
ALIGN_OUT_TOP_MID |
控件底部中点对齐到参考对象顶部中点 |
ALIGN_OUT_TOP_RIGHT |
控件右下角对齐到参考对象右上角 |
ALIGN_OUT_BOTTOM_LEFT |
控件左上角对齐到参考对象左下角 |
ALIGN_OUT_BOTTOM_MID |
控件顶部中点对齐到参考对象底部中点 |
ALIGN_OUT_BOTTOM_RIGHT |
控件右上角对齐到参考对象右下角 |
ALIGN_OUT_LEFT_TOP |
控件右上角对齐到参考对象左上角 |
ALIGN_OUT_LEFT_MID |
控件右侧中点对齐到参考对象左侧中点 |
ALIGN_OUT_LEFT_BOTTOM |
控件右下角对齐到参考对象左下角 |
ALIGN_OUT_RIGHT_TOP |
控件左上角对齐到参考对象右上角 |
ALIGN_OUT_RIGHT_MID |
控件左侧中点对齐到参考对象右侧中点 |
ALIGN_OUT_RIGHT_BOTTOM |
控件左下角对齐到参考对象右下角 |
说明: 全屏高斯模糊只支持1个控件持有,非全屏高斯模糊支持多个控件持有。如果高斯模糊在特定的模糊半径下的显示效果有方块感,建议添加蒙板来解决。
UIView的监听器介绍
UIView中定义了多种监听器,使用方式基本相同。用户需实例化监听器或者继承监听器,实现抽象函数,在执行具体操作时,会回调监听器中对应的回调函数。用户可以在回调函数中添加需要执行的逻辑。
下面分别介绍了UIView中定义的监听器。
-
OnClickListener,该监听器主要用来响应处理点击事件。
表 1 OnClickListener回调函数
函数 介绍 virtual bool OnClick(UIView& view, const ClickEvent& event) 当视图被点击时触发回调。
• 参数view:点击的视图。
• 参数event:点击事件。 返回值为bool类型:
• 返回true表示事件已经处理。
• 返回false表示事件未处理完成,会将该事件继续传递到父视图。 -
OnLongPressListener,该监听器主要用来响应处理长按事件。
表 2 OnLongPressListener回调函数
函数
介绍
virtual bool OnLongPress(UIView& view, const LongPressEvent& event)
当视图被长按时触发回调。
- 参数view:长按的视图。
- 参数event:长按事件。
返回值为bool类型:
- 返回true表示事件已经处理。
- 返回false表示事件未处理完成,会将该事件继续传递到父视图。
-
OnDragListener,该监听器主要用来响应处理拖动事件。
表 3 OnDragListener回调函数
以上函数中,
- 参数view:接受拖动事件的视图。
- 参数event:拖动事件。
返回值为bool类型:
- 返回true表示事件已经处理。
- 返回false表示事件未处理完成,会将该事件继续传递到父视图。
-
OnTouchListener,该监听器主要用于响应处理触摸事件。
表 4 OnTouchListener回调函数
以上函数中,
- 参数view:接受触摸事件的视图。
- 参数event:分别为按下/松开/取消事件。
返回值为bool类型:
- 返回true表示事件已经处理。
- 返回false表示事件未处理完成,会将该事件继续传递到父视图。
-
OnRotateListener,该监听器主要用于响应表冠事件。
表 5 OnRotateListener回调函数
以上函数中,
- 参数view:接受表冠事件的视图。
- 参数event:表示表冠事件。
返回值为bool类型:
- 返回true表示事件已经处理。
- 返回false表示事件未处理完成,会将该事件继续传递到父视图。
UIViewGroup介绍
UIViewGroup继承于UIView,常用函数如表1所示。
表 1 UIViewGroup核心函数
| 函数 | 介绍 |
|---|---|
| virtual void Add(UIView* view) | 添加一个子视图。如果入参视图已经有父视图,则无法加入。 |
| virtual void Insert(UIView prevView, UIView insertView) | 在prevView视图后插入一个子视图。 |
| virtual void Remove(UIView* view) | 从当前视图树中移除指定子视图,非释放子视图。 |
| virtual void RemoveAll() | 从当前视图树中移除所有子视图,非释放子视图。 |
| virtual void GetTargetView(const Point& point, UIView** last) override | 获取可见的、最上层的、可以响应指定坐标点的触摸事件的目标子视图。 |
| virtual void GetTargetView(const Point& point, UIView current, UIView target) override | 获取一个可见的、最上层的、可以响应指定坐标点的触摸事件的目标子视图(current)。获取一个最上层的视图包含指定的坐标点(target)。 |
| virtual void MoveChildByOffset(int16_t x, int16_t y) | 移动所有子视图。 |
| UIView* GetChildrenHead() const | 获取此视图组中的最前一个子视图。 |
| UIView* GetChildrenTail() const | 获取此视图组中的最后一个子视图。 |
| UIView GetChildById(const char id) const | 通过校验id,获取对应子视图。 |
| void SetDisallowIntercept(bool flag) | 设置是否拦截触摸事件至子视图。 |
| virtual UIView GetChildById(const char id) const override | 根据指定的id获取子控件。 |
| void SetAutoSize(bool state) | 设置该视图是否适应子控件的尺寸:自调整为能够包含所有子视图的尺寸。 |