HarmonyOS6 RcIcon 组件核心架构与字体图形渲染机制
HarmonyOS6 RcIcon 组件架构与渲染机制。支持字体与图片双模式,内置 492 个矢量符号。涵盖装饰器体系、字体注册、Unicode 映射、渲染路径决策。包含性能优化(加载、渲染、事件、缓存)、错误处理、扩展性及 ArkTS 规范适配策略,提供类型安全且高效的图标解决方案。

HarmonyOS6 RcIcon 组件架构与渲染机制。支持字体与图片双模式,内置 492 个矢量符号。涵盖装饰器体系、字体注册、Unicode 映射、渲染路径决策。包含性能优化(加载、渲染、事件、缓存)、错误处理、扩展性及 ArkTS 规范适配策略,提供类型安全且高效的图标解决方案。

RcIcon 是 rchoui 组件库中的核心基础组件,负责渲染各类图形化符号。它是一个高度灵活的图形显示组件,支持字体符号和图片两种渲染模式,内置 492 个精心设计的矢量符号(246 个线型 +246 个实底),能够满足绝大多数业务场景需求。
@ComponentV2
export struct RcIcon {
@Local baseStyle: RcUIBaseStyleObjType = AppStorageV2.connect(...)
@Local config: RcGlobalConfig = AppStorageV2.connect(...)
@Param @Require name: keyof RcIconDataType | ResourceStr
@Param color?: ResourceColor = undefined
@Param iconSize: RcStringNumber = this.baseStyle.fontSizeLg as string
// ... 其他属性
}
装饰器解析:
| 装饰器 | 作用 | 应用场景 |
|---|---|---|
@ComponentV2 | HarmonyOS6 新一代组件定义 | 性能更优,类型推断更强 |
@Local | 连接全局状态 | 全局样式、配置响应式同步 |
@Param | 组件参数定义 | 接收外部传入的配置 |
@Require | 必需参数标记 | 确保关键参数不为空 |
@Event | 事件回调定义 | 处理用户交互事件 |
┌─────────────────────────────────────────┐
│ RcIcon 组件 │
├─────────────────────────────────────────┤
│ ┌────────────┐ ┌────────────┐ │
│ │ 参数层 │ ───> │ 判断层 │ │
│ │ Props │ │ Type Check│ │
│ └────────────┘ └────────────┘ │
│ │ │ │
│ ├──────────┬────────┤ │
│ │ ▼ ▼ ▼ │ │
│ ┌─────────┐ ┌────────┐ ┌────────┐ │
│ │ 字体符号 │ │ 在线图片│ │ 本地资源│ │
│ └─────────┘ └────────┘ └────────┘ │
│ │ │ │ │
│ │ ▼ ▼ ▼ │ │
│ ┌─────────────────────────────┐ │
│ │ 渲染层 (build) │ │
│ │ Text 组件 或 Image 组件 │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────────┘
// 全局样式依赖
@Local baseStyle: RcUIBaseStyleObjType = AppStorageV2.connect(RcUIBaseStyle, RcStorageKey.BASE_STYLE)!
// 全局配置依赖
@Local config: RcGlobalConfig = AppStorageV2.connect(RcGlobalConfig, RcStorageKey.GLOBAL_CONFIG)!
AppStorageV2 连接机制:
aboutToAppear(): void {
if (!this.fontRegistered) {
try {
let font: Font = this.getUIContext().getFont();
font.registerFont({
familyName: 'rcFont',
familySrc: $rawfile('rc_font.woff')
});
this.fontRegistered = true;
} catch (error) {
console.error('RcIcon: Font registration failed', error);
}
}
}
注册流程详解:
组件挂载 (aboutToAppear)
│
▼
检查 fontRegistered 标志
├── 已注册 ──> 跳过
└── 未注册 ──> 获取 UIContext
│
▼
获取 Font 管理器
│
▼
调用 registerFont()
├── 成功 ──> fontRegistered = true
└── 失败 ──> 记录错误日志
关键点分析:
aboutToAppear 生命周期注册,确保渲染前字体可用fontRegistered 标志避免重复注册// config.ets 中的映射表
export const RcIconList: RcIconDataType = {
"icon-houi_home": "\ue7c7",
"icon-houi_heart": "\ue71b",
"icon-houi_star": "\ue784",
"icon-houi_search": "\ue77a",
// ... 492 个符号映射
};
映射表结构:
| 符号名称 | Unicode 编码 | 用途 |
|---|---|---|
icon-houi_home | \ue7c7 | 主页 |
icon-houi_heart | \ue71b | 收藏/喜欢 |
icon-houi_star | \ue784 | 星标/评分 |
icon-houi_search | \ue77a | 搜索 |
字符获取逻辑:
private getIconContent(): string {
if (typeof this.name === 'string') {
// 使用 Object 方式访问以符合 ArkTS 规范
return Object(RcIconList)[this.name as string] || this.name;
}
return '';
}
处理流程:
build() {
if (typeof this.name === "string" && !this.isOnlineImage()) {
Text(this.getIconContent())
.fontFamily('rcFont')
.fontColor(this.color)
.fontSize(getSizeByUnit(this.iconSize, true))
.borderRadius(getSizeByUnit(this.iconRadius))
.animation(this.iconAnimation)
.onTouch(this.handleTouch);
} else {
// Image 渲染逻辑
}
}
渲染步骤解析:
参数判断
│
▼
是否为字符串类型?
├── 是 ──> 是否为在线图片 URL?
│ │
│ ├── 否 ──> 【字体渲染路径】
│ │ │
│ │ ├─> 获取 Unicode 字符
│ │ ├─> 设置字体族 (rcFont)
│ │ ├─> 应用颜色样式
│ │ ├─> 应用尺寸样式
│ │ ├─> 应用圆角样式
│ │ ├─> 应用动画效果
│ │ └─> 绑定触摸事件
│ │
│ └── 是 ──> 【图片渲染路径】
│
└── 否 ──> 【ResourceStr 路径】(本地资源)
private isOnlineImage(): boolean {
return typeof this.name === 'string' && this.name.startsWith("http");
}
判断逻辑:
private isSingleUnicodeEscape(str: string): boolean {
return str.length === 1 && /^[�-]$/.test(str);
}
验证条件:
应用场景:
name 参数类型
├─ ResourceStr (Resource 类型)
│ └──> Image 组件 (本地资源)
└─ string (字符串)
├─ 以 "http" 开头
│ └──> Image 组件 (在线图片)
└─ 其他字符串
├─ 存在于 RcIconList 映射表
│ └──> Text 组件 + Unicode 字符
└─ 不存在于映射表
└──> Text 组件 + 原始字符串
单次加载机制:
private fontRegistered: boolean = false;
aboutToAppear(): void {
if (!this.fontRegistered) {
// 注册字体逻辑
this.fontRegistered = true;
}
}
优势:
build() {
if (typeof this.name === "string" && !this.isOnlineImage()) {
// Text 组件分支
} else {
// Image 组件分支
}
}
优化策略:
private handleTouch = (event: TouchEvent): void => {
if (event.type === TouchType.Up) {
this.onIconClick(event);
}
};
优化点:
.fontSize(getSizeByUnit(this.iconSize, true))
.borderRadius(getSizeByUnit(this.iconRadius));
getSizeByUnit 工具函数特点:
try {
let font: Font = this.getUIContext().getFont();
font.registerFont({
familyName: 'rcFont',
familySrc: $rawfile('rc_font.woff')
});
this.fontRegistered = true;
} catch (error) {
console.error('RcIcon: Font registration failed', error);
}
容错策略:
private getIconContent(): string {
if (typeof this.name === 'string') {
return Object(RcIconList)[this.name as string] || this.name;
}
return '';
}
回退机制:
@Param @Require name: keyof RcIconDataType | ResourceStr;
TypeScript 类型约束:
keyof RcIconDataType:限制为已定义的符号名称ResourceStr:支持 HarmonyOS 资源引用@Require:确保必需参数不为空@Param fontName: ResourceStr = "";
// 渲染时应用自定义字体
Text(this.getIconContent()).fontFamily(this.fontName || 'rcFont');
扩展场景:
组件提供了丰富的样式属性:
color:颜色定制iconSize:尺寸调整iconRadius:圆角控制iconAnimation:动画效果设计原则:
@Event onIconClick: (event: TouchEvent) => void = () => {};
事件系统特点:
// 符合 ArkTS 规范的访问方式
return Object(RcIconList)[this.name as string] || this.name;
// 不推荐的方式(可能不符合 ArkTS 严格模式)
// return RcIconList[this.name]
原因分析:
Object() 包装确保类型安全// 接口定义清晰
export interface RcIconDataType extends OutLineIconsType, FilledIconsType {}
// 参数类型明确
@Param name: keyof RcIconDataType | ResourceStr;
规范要点:
通过条件判断选择不同的渲染策略:
getIconContent() 方法作为工厂方法,根据输入产生不同的内容:
字体注册采用单例思想:
fontRegistered 标志确保全局只注册一次
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online