跳转至

UIKit 振动、多语言与资源

振动支持

功能介绍

滑动或旋转表冠时,振动控件可以触发振动反馈,具体振动行为由外部通过VibratorManager注册。

说明: 如果要启动振动,需要提前打开宏定义ENABLE_VIBRATOR并注册振动函数。

振动类型

振动类型说明如下:

enum class VibratorType {
    VIBRATOR_TYPE_ONE, // 振动1次
    VIBRATOR_TYPE_TWO, // 振动2次
    VIBRATOR_TYPE_THREE // 振动3次
};

对外接口

表 1 VibratorManager核心函数

函数

说明

void RegisterVibratorFunc(VibratorFunc vibratorFunc)

注册振动函数,类型VibratorFunc的定义为

typedef void(*VibratorFunc)(VibratorType vibratorType);。

VibratorFunc GetVibratorFunc()

获取当前振动函数。

表 2 支持振动的控件

控件

触发与说明

UIRollerView

滚轮控件;旋转交互是否触发振动由外部注册的振动函数和目标配置决定。

UIList

旋转选择项时触发二次或三次振动。

UIScrollView

旋转滚动时按步长触发一次振动,到达边界时触发三次振动。

UISlider

旋转调节值发生变化时触发二次或三次振动。

UISwipeView

旋转切换页面时根据当前位置触发一次或三次振动。

多语言切换

功能介绍

多语言切换主要提供的是字符串自动翻译功能,通过字符串ID自动查找对应语言的字符串,并提供了一个工具将xml转换为bin文件和对应的C++头文件。

语言代码参考网站:http://www.lingoes.cn/zh/translator/langcode.htm

转换工具及使用请参考Debugkits指导文档《DebugKits工具使用指南》中的“多语言脚本调用”章节

图 1 原理框图

原理框图

对外接口

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:支持多字库。

图 1 多字言文本混排效果

多字言文本混排效果

关键对外接口

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端对图片资源的压缩打包,是指使用项目(工具组)提供的资源打包工具依据xml文件配置的压缩算法以及像素格式信息,将指定目录下的每一个子目录都打包成一个资源文件,并生成资源索引文件ui_resource_image.h;或者将指定目录下的每一个图片文件都打包成一个资源文件。

ui_resource_image.h存储了每一个被处理过的图片的index值,以便板端可以快速从打包的文件中定位到图片内容,具体可以参考后续的设计描述。

在板端,如果是单个目录打包成一个资源文件,ImageCacheManager需要基于ui_resource_image.h中保存的图片索引信息从资源文件中解析出图片内容,否则ImageCacheManager可以直接从资源文件中解析出图片内容。然后,ImageCacheManager利用系统提供的内存池机制对图片内容进行缓存。为了屏蔽芯片和系统的差异,我们使用MemPoolManager+Gralloc+LOS_MEM的结构对内存池进行管理。另外,ImageCacheManager也同时提供移除图片资源的接口,以便PSRAM内存资源得到充分利用。

注意,图片的压缩算法以及解压方案不是本方案的重点(UIKit属于使用方),本文不再赘述。

图 1 方案总体实现原理图

方案总体实现原理图

服务器要求

由于图片资源转换成bin格式文件、图片压缩、解压等操作是通过Python工具完成的。想要使用此功能,需要对服务器安装这两个工具。

pip install opencv-python
pip install Pillow

图片资源打包

图片资源打包工具的功能如下:依据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
  • 命令格式:

    python images_tool.py –p [dir|file] –c config.xml -i <Input Dir> -o <Output Dir> -t <Dir>
    

    说明:

    • -p:指定打包方式。
    • file:以每个图片为单位进行打包。
    • dir:将图片进行打包后,再以子文件夹为单位将其包含的已打包的图片再一起打包。
    • -c:配置文件,指定打包的压缩算法、像素格式以及宽度对齐值。

      • 压缩算法可选:HFBC|HFBC_ABYPASS
      • 像素格式可选:RGB565|RGB888|ARGB8888
    • -i:指定待处理图片的根目录,图片目录下的图片可以为.jpg、.png、.bmp格式。

    • -o:指定输出的文件夹。
    • -t:指定头文件ui_resource_image.h生成的目录,仅在dir打包方式下生效。
    • -e:指定需要解压的文件路径,文件类型为.bin。
    • -f:指定解压后图片输出的路径。

    输入限制:子文件夹名以及文件名必须为数字以及字母的组合。

打包使用

  • 多图片按照目录打包命令如下:

    python images_tool.py –p dir –c config.xml -i <Input Dir> -o <Output Dir>
    
  • 单图片打包命令如下:

    python images_tool.py –p file –c config.xml -i <Input Dir> -o <Output Dir>
    

资源使用

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文件的路径。