UIKit 振动、多语言与资源
振动支持
功能介绍
滑动或旋转表冠时,振动控件可以触发振动反馈,具体振动行为由外部通过VibratorManager注册。
说明: 如果要启动振动,需要提前打开宏定义ENABLE_VIBRATOR并注册振动函数。
振动类型
振动类型说明如下:
enum class VibratorType {
VIBRATOR_TYPE_ONE, // 振动1次
VIBRATOR_TYPE_TWO, // 振动2次
VIBRATOR_TYPE_THREE // 振动3次
};
对外接口
表 1 VibratorManager核心函数
函数 |
说明 |
|---|---|
注册振动函数,类型VibratorFunc的定义为 typedef void(*VibratorFunc)(VibratorType vibratorType);。 |
|
获取当前振动函数。 |
表 2 支持振动的控件
控件 |
触发与说明 |
|---|---|
滚轮控件;旋转交互是否触发振动由外部注册的振动函数和目标配置决定。 |
|
旋转选择项时触发二次或三次振动。 |
|
旋转滚动时按步长触发一次振动,到达边界时触发三次振动。 |
|
旋转调节值发生变化时触发二次或三次振动。 |
|
旋转切换页面时根据当前位置触发一次或三次振动。 |
多语言切换
功能介绍
多语言切换主要提供的是字符串自动翻译功能,通过字符串ID自动查找对应语言的字符串,并提供了一个工具将xml转换为bin文件和对应的C++头文件。
语言代码参考网站:http://www.lingoes.cn/zh/translator/langcode.htm
转换工具及使用请参考Debugkits指导文档《DebugKits工具使用指南》中的“多语言脚本调用”章节。

对外接口
FontGlobalManager
FontGlobalManager为全球化文字管理模块,用户需要将多语言信息注册到该模块,通过SetCurrentLangId函数进行语言切换,其他接口为内部模块使用,外部模块可以忽略。
表 1 FontGlobalManager核心函数
| 函数 | 说明 |
|---|---|
| static FontGlobalManager* GetInstance() | FontGlobalManager是单例,该接口用于获取文字全球化管理的实例。 • 参数:N/A • 返回值类型:FontGlobalManager* |
| bool RegisterLanguageInfo(const char** langFile, uint8_t langNum, uint8_t defaultLangId) | 注册语言信息。 • 参数1:const char** resFile,字符串二进制文件数组首地址,每个二进制文件对应一种语言。 • 参数2:uint8_t totalLangId,文件最大个数(最大值参考 ui_resource_string.h,且不可超出实际注册语言个数)。 • 参数3:uint8 defaultLangId,默认的语言ID(ID值参考ui_resource_string.h)。 返回值类型:bool。 • true 代表成功。 • false代表失败。 |
| void UnRegisterLanguageInfo() | 卸载所有的多语言字串信息。 • 传参:N/A • 返回值类型:void |
| void SetCurrentLangId(uint8_t langId) | 设置当前的语言 • 传参:uint8_t langId (ID值参考ui_resource_string.h) • 返回值类型:void |
| FontParam GetFontParam(uint16_t textId) | 获取当前的语言。 • 传参:uint8_t textId , 文本ID,(ID值参考ui_resource_string.h) • 返回值类型:FontParam(fontSize, direct, fontName) |
| uint8_t GetTotalLangId() | 获取支持的多语言数量。 • 参数:N/A • 返回值类型:uint8_t 最大的语言ID。 |
UILabelExt和UILabelButtonExt
多语言切换功能是以UIKit扩展方式实现的,为了尽量减少对原始UIKit的修改,扩展了两个组件,分别为UILabelExt和UILabelButtonExt。如果控件需要支持多语言切换,需要将UILabel和UILabelButton切换到UILabelExt和UILabelButtonExt,并通过SetTextId来设置静态文本。ForceResetText在切换语言时由FontGlobalManager调用,用户无需调用该接口。
表 1 UILabelButtonExt核心函数
| 函数 | 描述 |
|---|---|
| void SetTextId(uint16_t textId) | 设置TextId。 • 参数:uint16_t textId • 返回值:void |
| void ForceResetText() override | 强制根据控件内部的TextId设置文本内容。 • 参数:N/A • 返回值:void |
XML APIs
根元素
XML必须以language为根元素并支持以下属性,language元素中的属性对所有的子元素都生效,并且作为子元素的默认值,如果子元素有定义相同的属性,以子元素设置的生效。
表 1 多语言xml配置
属性名 |
描述 |
取值 |
必选 |
|---|---|---|---|
languageinfo |
语言信息,使用语言代码(ISO 639)标识语言。 |
ISO 639标准定义的语言代码 |
是 |
direct |
文本方向布局。 |
ltr(left to right),rtl(right to left),mixed(多语言混排) |
否 |
fontName |
设置矢量字库名,路径需要在graphic_config.h中配置宏VECTOR_FONT_DIR。 |
ttf文件名 |
否 |
字符串元素
字符串元素以lanstr为命名,定义字符串的相关信息,包括字符串取值、文本大小、字库名等信息。如果根元素也定义的相同的属性,会以字符串元素中定义的值为准,如果都没有定义,取UIKit中设置的默认值。
表 1 字符串元素配置
属性名 |
描述 |
取值 |
必选 |
|---|---|---|---|
id |
字符串唯一标识,需要保证唯一性。 |
统一以STR_ 为前缀 |
是 |
value |
字符串内容。 |
任意字符串 |
是 |
direct |
文本方向布局。 |
ltr(left to right),rtl(right to left),mixed(多语言混排) |
否 |
size |
文本大小,如果同时有在代码中通过接口SetFont进行设置,会按照和SetText以及ForceResetText先后顺序为准。 |
0~255 |
否 |
fontName |
设置矢量字库名,路径需要在graphic_config.h中配置宏VECTOR_FONT_DIR。 注意:UILabelExt和UILabelButtonExt不建议显式调用SetFont配置字库,而应该通过fontName字段配置;如果要配置font的大小,可以将void SetFont(const char* name, uint8_t size);第一个参数配置为空。 |
ttf文件名 |
是 |
多语言文本显示
功能介绍
为了支持多语言文本的显示,UIKit提供了如下文本显示功能:
- 支持注册多字库以及设置备选字库。
- 支持复杂语系文本的整形。
- 支持多语言文本(无论是否是复杂语系)的混排。
- 支持文本的RTL、LTR以及MIXED(多语言文本混排场景)显示。
- 支持ICU换行规则。
以上功能限定于定制控件UILabelExt和UILabelButtonExt,并且需确保graphic_config.h中下述宏的值均为1(默认均为1)。
- ENABLE_SHAPING :支持整形,依赖于ENABLE_ICU。
- ENABLE_ICU:支持ICU(ICU换行要依赖规则文件“line_cj.brk”,确保文件“line_cj.brk”在目录“/user/res/”下)。
- ENABLE_MULTI_FONT:支持多字库。

关键对外接口
UIFont提供接口支持注册多字库,UIMultiFontManager提供接口支持配置字库的搜索顺序,两者配合即可实现基于多字库显示多语言文本的功能。ICU换行、整形以及混排功等功能需要使用UILabelExt和UILabelButtonExt两个控件,由系统内部处理,开发者并不可见。
表 1 关键对外接口
| 类 | 接口 | 说明 |
|---|---|---|
| UIFont | uint8_t RegisterFontInfo(const char* ttfName, uint8_t shaping = 0) | 注册系统字库。 • 参数ttfName:字库名。 • 参数shaping:当前字库是否包含整形的字形数据。 返回注册字库的ID。 注意:向系统依次注册要使用的字库文件,但第一个需为不包含整形字形数据的字库。需将返回的fontId保存,为后续设置字库搜查表所用。 |
| UIFont | uint8_t RegisterFontInfo(const UITextLanguageFontParam* fontsTable, uint8_t num) | 一次性注册多个系统字库。 • 参数fontsTable:指向多个字库结构体数组的指针,字库ID保存在字库结构体中。 • 参数num:字库结构体数组的个数。 |
| UILabel/UILabelButton | void SetDirect(UITextLanguageDirect direct) | 设置文本的方向。 • 参数direct: 文本方向,TEXT_DIRECT_LTR / RTL / MIXED。 注意:对于混排并且方向不一致的多语言文本,开发者需要将文本方向设置为TEXT_DIRECT_MIXED |
| UILabel/UILabelButton | void SetFont(const char* name, uint8_t size) | 设置当前Label使用的字库。 • 参数name: 字库名,如果为nullptr,则只刷新字体大小。 • 参数direct: 字体大小。 |
| UILabel/UILabelButton | void SetFontId(uint8_t fontId) | 设置当前字库。 • 参数fontId: 注册字库时返回的字库ID。 |
| UIMultiFontManager | int8_t SetSearchFontList(uint16_t fontListId, uint16_t* fontIds, uint8_t size) | 配置备选字库。如果当前字库id为fontListId,当出现不识别的字符时,则依次在fontIds所对应的备选字库中查找字符。 • 参数fontListId:字库ID值,保存为搜查表的key值。 • 参数fontIds:待搜索的字库ID值数组,保存在搜查表的Value值中。 • 参数size:待搜索的字库ID值数组的长度。 |
开发建议
- 字库注册可以依次一个一个地注册多个字库,也可以一次性注册多个字库。
- 无论是哪种注册方式,支持整形的字库均不能第一个注册。
- 注册支持整形的字库,字库名必须包含并且仅包含一个匹配字段:Arabic、Thai、Myanmar、Devanagari、Hebrew、Bengali,用于快速基于unicode找到所在的整形字库。
- 文本控件建议优先使用扩展控件UILabelExt、UILabelButtonExt,以便支持多语言切换、整型、ICU换行等功能。
- 文本控件如果使用多语言切换功能(SetTextId),系统会自动配置匹配的字库,字体大小通过接口SetFont(nullptr, size)指定。
- 文本控件如果不使用多语言切换功能,必须显式指定匹配的字库;否则会导致文本显示不出来,或者由于备选字库搜索时间过长导致显示卡顿。
- 文本控件如果包含有方向不一致的多语言文本,那么必须将文本方向设置为TEXT_DIRECT_MIXED。
- UIMultiFontManager::SetSearchFontList可以动态指定特定字库的备选字库:若当前字库不包含待处理的字符,则依次在其备选字库中查找。
- 备选字库根据混排文本的内容来确定,如果备选字库配置的不合理,则会导致混排文本中的非主文本显示不出来,或者因为备选字库搜索时间过长导致文本显示卡顿。
图片资源管理
方案目的
在IOT的产品中,从eMMC(一种嵌入式、非易失存储系统)中直接读取图片资源的速度比较慢。如果在图片绘制的过程中,每次都从eMMC中读取图片资源,那么UI的显示就会比较卡顿。因此,为了提升图片读取效率,则需要将图片资源提前缓存到PSRAM(伪静态随机存取器)指定区域中,后续的读取可直接从PSRAM中读取,从而提升图片加载效率。
另外,PSRAM由于成本问题,其内存的大小是严格受限的(目前可实现存储容量有:32M、64M、256M)。因此,需要将图片资源进行离线压缩,在PSRAM内存大小不变的情形下,可以缓存更多的图片资源。与此同时,还需要支持硬件对图片进行解压,以便减小图片压缩对显示性能的影响。
总之,该方案是为了在PSRAM受限的情形下,以更高的效率缓存和显示图片资源。
整体功能介绍
图片资源管理的总体方案主要分为两部分:
- PC端对图片资源的压缩打包。(请参考《DebugKits工具使用指南》中的“图形压缩对比”章节)
- 板端解析图片资源,并将其缓存到内存池中。
PC端对图片资源的压缩打包,是指使用项目(工具组)提供的资源打包工具依据xml文件配置的压缩算法以及像素格式信息,将指定目录下的每一个子目录都打包成一个资源文件,并生成资源索引文件ui_resource_image.h;或者将指定目录下的每一个图片文件都打包成一个资源文件。
ui_resource_image.h存储了每一个被处理过的图片的index值,以便板端可以快速从打包的文件中定位到图片内容,具体可以参考后续的设计描述。
在板端,如果是单个目录打包成一个资源文件,ImageCacheManager需要基于ui_resource_image.h中保存的图片索引信息从资源文件中解析出图片内容,否则ImageCacheManager可以直接从资源文件中解析出图片内容。然后,ImageCacheManager利用系统提供的内存池机制对图片内容进行缓存。为了屏蔽芯片和系统的差异,我们使用MemPoolManager+Gralloc+LOS_MEM的结构对内存池进行管理。另外,ImageCacheManager也同时提供移除图片资源的接口,以便PSRAM内存资源得到充分利用。
注意,图片的压缩算法以及解压方案不是本方案的重点(UIKit属于使用方),本文不再赘述。

服务器要求
由于图片资源转换成bin格式文件、图片压缩、解压等操作是通过Python工具完成的。想要使用此功能,需要对服务器安装这两个工具。
图片资源打包
图片资源打包工具的功能如下:依据xml文件配置的压缩算法以及像素格式信息,将指定目录下的每一个子目录都打包成一个资源文件,并生成资源索引文件ui_resource_image.h;或者将指定目录下的每一个图片文件都打包成一个资源文件。
配置文件说明
<!-- 注意,compress和format必须同时配置;align可选,默认为1 -->
<!-- 注意,如果定制了文件的配置,其父目录也必须配置 -->
<!-- 指定默认的压缩算法、像素格式以及非压缩的宽度对齐值 -->
<!-- 以CS方式压缩:tile压缩单元宽度、alpha压缩模式、rgb压缩模式、ver压缩方式输入为1-->
<!-- CS、ES打包都应保证输入文件夹有图片可以压缩-->
<!-- 三种压缩模式的选择可以通过xml文件进行配置,但RGB565除外需要手动配置format="RGB565"-->
<imageRes compress="HFBC" tile="6" alpha="1" rgb="1" autocmpmode="0" highqualitymode="0" highcmpratiomode="0" ver="1">
</imageRes>
<!-- 以ES方式压缩:ver压缩方式输入为0-->
<imageRes compress="HFBC" autocmpmode="0" highqualitymode="0" highcmpratiomode="0" ver="0">
</imageRes-->
表 1 图片资源打包工具配置
标签 |
属性 |
说明 |
|---|---|---|
imageRes |
- |
根标签。 |
compress |
指定默认压缩算法,取值可为:HFBC|HFBC_ABYPASS。 |
|
format |
指定默认像素格式,取值可为:RGB565|RGB888|ARGB8888。 |
|
imageDir |
- |
imageRes的子标签,用于标识存放图片的文件夹。 |
name |
文件夹名,可以指定为APP的名字,或者场景名,不与APP强绑定。 |
|
compress |
指定该文件夹下的图片文件的默认压缩算法,优先级高于imageRes指定的compress属性值。 |
|
format |
指定该文件夹下的图片文件的默认像素格式,优先级高于imageRes指定的format属性值。 |
|
imageFile |
- |
imageDir的子标签,用于标识具体某一个文件。 |
name |
文件名。 |
|
compress |
指定特定图片文件的压缩算法,优先级高于imageDir指定的compress属性值。 |
|
format |
指定特定图片文件的像素格式,优先级高于imageDir指定的format属性值。 |
工具输入要求
- 工具建议命名为:images_tool.py
-
命令格式:
说明:
- -p:指定打包方式。
- file:以每个图片为单位进行打包。
- dir:将图片进行打包后,再以子文件夹为单位将其包含的已打包的图片再一起打包。
-
-c:配置文件,指定打包的压缩算法、像素格式以及宽度对齐值。
- 压缩算法可选:HFBC|HFBC_ABYPASS
- 像素格式可选:RGB565|RGB888|ARGB8888
-
-i:指定待处理图片的根目录,图片目录下的图片可以为.jpg、.png、.bmp格式。
- -o:指定输出的文件夹。
- -t:指定头文件ui_resource_image.h生成的目录,仅在dir打包方式下生效。
- -e:指定需要解压的文件路径,文件类型为.bin。
- -f:指定解压后图片输出的路径。
输入限制:子文件夹名以及文件名必须为数字以及字母的组合。
打包使用
-
多图片按照目录打包命令如下:
-
单图片打包命令如下:
资源使用
ImageCacheManager是对外的唯一接口类。按照资源文件类型,可分为多资源文件以及单资源文件,通过对外接口可加载和卸载文件中的资源数据。
须知: 如果用户需要自行填充ImageInfo,请先使用void* ImageCacheMalloc(ImageInfo& info)接口申请ImageInfo所需的内存,然后再进行数据填充,不建议使用其他系统接口申请内存。
表 1 ImageCacheManager核心函数
| 函数 | 介绍 |
|---|---|
| bool LoadAllInMultiRes(const std::string& file, FILE* userFP = nullptr, bool isLongTerm = false, int offset = 0) | 一次性加载多资源文件中的所有资源,并为这些资源分配整块内存。 • file:图片bin文件的路径。 • userFP:文件指针(在外部打开),如果userFP不为nullptr,将首先使用它。 • isLongTerm:图片是否应该长期保存。 • offset:多图起始点的偏移量,主要与userFP(非nullptr)配合使用。 |
| bool LoadAllInMultiRes(uint8_t* buf) | 一次从输入缓冲区加载全部图片资源。之后使用LoadOneInMultiRes来获取实际的图像。 buf:图片bin文件在内存中的地址。 |
| ImageInfo LoadOneInMultiRes(uint32_t resId, const std::string& file, FILE userFP = nullptr, bool isLongTerm = false, int offset = 0) | 加载多资源文件中的单个指定资源,并为其分配内存。如果之前已经加载过镜像,那么它将直接返回缓冲区。 • resId:要加载的图片的资源ID。 • 其他:意义与LoadAllInMultiRes相同。 |
| ImageInfo LoadOneInMultiRes(uint8_t buf, uint32_t resId); | 加载多资源文件中的单个指定资源,并为其分配内存。如果之前已经加载过镜像,那么它将直接返回缓冲区。 • buf:图片bin文件在内存中的地址。 • resId:要加载的图片的资源ID。 |
| bool UnloadOneInMultiRes(uint32_t resId, const std::string& file) | 卸载通过LoadOneInMultiRes的方式加载的单个资源。 • resId:要卸载的图片的资源ID。 • file:图片bin文件的路径。 |
| bool UnloadOneInMultiRes(uint8_t* buf, uint32_t resId) | 卸载通过LoadOneInMultiRes的方式加载的单个资源。 • buf:图片bin文件在内存中的地址。 • resId:要卸载的图片的资源ID。 |
| bool UnloadAllInMultiRes(const std::string& file) | 卸载多资源文件中已加载的资源。 file:图片bin文件的路径。 |
| bool UnloadAllInMultiRes(uint8_t* buf) | 卸载多资源文件中已加载的资源。 buf:图片bin文件在内存中的地址。 |
| ImageInfo* LoadSingleRes(const std::string& file, bool isLongTerm = false) | 加载单资源文件中的资源。 • file:图片bin文件的路径。 • isLongTerm:图片是否应该长期保存。 |
| bool UnloadSingleRes(const std::string& file) | 卸载单资源文件中的资源。 file:图片bin文件的路径。 |