Flutter三方库适配OpenHarmony【图标库】harmony_icons 使用详解:从单个图标到数据驱动的 6 大实用用法
前言
harmony_icons 是把鸿蒙官方 HM Symbol 图标字体搬上 Flutter 的零依赖三方库:534 个官方图标、17 个分类、每个图标自带中文名/模块/最低系统版本等元数据,用法与 cupertino_icons 完全一致。上一篇《harmony_icons 全解》讲清了它的背景、架构与鸿蒙适配原理;这一篇只谈"怎么用"——站在应用开发者的视角,把六大典型用法逐一拆解成可直接抄进项目的代码:
- 静态常量:工具栏、Tab、悬浮按钮里的图标怎么选、怎么调;
- 数据驱动:服务端下发图标名怎么安全渲染;
- 图标市场:遍历、分类筛选、搜索匹配的完整实现;
- 元数据驱动 UI:中文名、模块、版本兼容性提示怎么上界面;
- 高级渲染:RTL 镜像与
wght可变字重; - 实战页面:把以上能力组合进真实页面,并在鸿蒙模拟器上运行验证。
文中所有图标名(如 OhosIcons.person_badge_plus、OhosIcons.checkmark_circle_fill)均核对过仓库生成源码,真实存在,可直接复制运行。
建议搭配阅读:《Flutter三方库适配OpenHarmony【图标库】HarmonyOS Symbol官方图标字体上Flutter:harmony_icons 全解》,本文是其"使用篇"。
一、阅读本文前:先明确你要解决哪类问题
1.1 图标库的三种使用姿势
拿到一个图标库,开发者通常要解决三类问题:
| 姿势 | 典型场景 | 对应本文章节 |
|---|---|---|
| 写死常量 | 固定 UI:按钮、Tab、空状态、角标 | 三 |
| 动态取图标 | 服务端配置、路由表、低代码下发图标名 | 四 |
| 批量浏览/选择 | 图标市场、主题选择器、图标预览工具 | 五 |
harmony_icons 的 API 恰好为这三类姿势各留了专门的入口:OhosIcons.<name> 常量、OhosIcons.fromName(name)、OhosIcons.values / categories / info。第六、七章再补充元数据展示与高级渲染,第八章给出一个把全部能力串起来的实战页面。
1.2 为什么鸿蒙上的图标用法值得单独讲
在官方 Flutter 里用图标库早就有成熟套路,但在鸿蒙(OpenHarmony)上,有两个额外变量值得先交代:
- 平台链路不同:鸿蒙分叉 CPF-Flutter/flutter_flutter 的字体加载、HAP 打包链路与 Android/iOS 不同,图标字体能否正确进包是第一个要验证的点;
- 视觉标准不同:鸿蒙应用期望使用 HarmonyOS Symbol 这套与系统同源的图标语言,而不是 Material/Cupertino 风格——这正是
harmony_icons存在的意义。
好消息是:由于本库是纯 Dart + 字体实现,Dart 侧的写法在两个平台上完全一致,平台差异只存在于构建与验证环节(第二章会给出验证方法)。
二、使用前准备:依赖、环境与冒烟验证
2.1 添加依赖
在 pubspec.yaml 中加入依赖并拉取:
dependencies:
harmony_icons: ^0.1.0
flutter pub get
导入只需一行,库入口会导出全部 API:
import 'package:harmony_icons/harmony_icons.dart';
字体在库的 pubspec 中已声明(family 固定为 HMSymbol,asset 为子集化后的 assets/fonts/HMSymbol.ttf),使用方无需任何字体配置。
2.2 冒烟验证:先确认字体加载正常
图标库出问题的经典症状是"图标变成方块/问号"。写业务代码之前,先用 10 行代码做冒烟验证,一次性确认字体加载、码点映射、fontPackage 跨包引用三件事:
class IconSmokeTest extends StatelessWidget {
const IconSmokeTest({super.key});
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
// 静态常量
Icon(OhosIcons.wifi, size: 40),
// 动态查询
Icon(OhosIcons.fromName('airplane_fill'), size: 40),
// 元数据
Text('count=${OhosIcons.count} v${OhosIcons.version} '
'cat=${OhosIcons.categories.length}'),
],
),
);
}
}
运行后的判定标准:
- 两个图标正常渲染字形(不是方块
□、不是?、不是空白); - 文本输出
count=534 v2.3 cat=17(图标总数、数据版本、分类数); - 控制台无字体加载相关异常。
提示:如果在鸿蒙工程(
example/ohos这类壳工程)上冒烟失败,先确认 ohos 壳执行过ohpm install且整包重新构建——字体是随 HAP 资源打包的,旧构建产物里可能没有新字体。
| 症状 | 最可能原因 | 处理 |
|---|---|---|
| 图标是方块/问号 | 字体未进包 / fontPackage 被覆盖 | 重新构建;检查是否手写了 fontPackage: null |
| 图标是空白(无方块) | 码点映射错误 | 确认用的是 OhosIcons 常量或 fromName,不要手写码点 |
fromName 抛 ArgumentError | 图标名不存在 | 先 OhosIcons.info.containsKey(name) 判断(见第四章) |
| 某图标渲染成别的图标 | 误用镜像码点 | 检查是否混用了 mirrorIcon |
三、用法一:静态图标常量(最高频)
3.1 在 Icon 与 IconButton 中使用
绝大多数场景就是"固定位置放一个固定图标",直接用 OhosIcons.<name> 常量:
Scaffold(
appBar: AppBar(
title: const Text('消息'),
actions: [
IconButton(
icon: Icon(OhosIcons.bell, size: 22),
onPressed: _openNotifications,
),
],
),
floatingActionButton: FloatingActionButton(
tooltip: '新增联系人',
child: Icon(OhosIcons.person_badge_plus, size: 24),
onPressed: _addContact,
),
)
命名规则与官网一致:英文小写下划线(airplane_fill、battery_100percent),_fill 后缀表示实心变体(如 bell 空心 / bell_fill 实心)。拿不准有哪些名字时,两个查找渠道:
- IDE 补全:输入
OhosIcons.即可看到全部 534 个常量,每个常量的文档注释带"中文名 · 英文名 · 最低版本"; - gallery 示例:仓库
example/自带图标市场应用(第八章有运行截图),支持中英文名搜索与分类筛选。
3.2 尺寸与颜色控制
OhosIcons 常量就是标准 IconData,Icon 的所有参数照常用:
// 状态栏风格的电池指示
Row(
children: [
Icon(OhosIcons.battery_100percent, size: 18, color: Colors.grey.shade600),
Icon(OhosIcons.wifi, size: 16, color: Colors.grey.shade600),
Icon(OhosIcons.airplane_fill, size: 16, color: Colors.orange),
],
)
size:像素尺寸,跟随字体渲染,任意缩放不失真(矢量字形);color:着色,单色图标可染成任意颜色;- 主题色建议:跟随
Theme.of(context).colorScheme,而不是写死Colors.x,保证深色模式下自动适配。
3.3 常见 UI 场景速查
| 场景 | 推荐图标 | 说明 |
|---|---|---|
| 返回 / 前进导航 | arrow_left / arrow_right、chevron_left / chevron_right | 细箭头 vs 小 V,按视觉重量选 |
| 刷新 / 重试 | arrow_2_circlepath、arrow_clockwise | 双圈循环 / 单圈循环 |
| 成功 / 失败 / 警示 | checkmark_circle_fill、xmark_circle、exclamationmark_triangle | 结果态三件套 |
| 空状态 | magnifyingglass、questionmark_circle | 搜索无结果 / 待补充信息 |
| 收藏 / 点赞 | star / star_fill、heart / heart_fill | 用 fill 变体表达"已激活" |
| 隐私 / 安全 | lock、bell_slash_fill | 锁定 / 免打扰 |
经验法则:同一界面里"空心↔实心"成对出现时,用同一图标名的两个变体(
bell↔bell_fill),视觉一致性最好;不要拿两个相似但不同源的图标混搭。
四、用法二:数据驱动的动态图标(fromName)
4.1 fromName 与安全查询
当图标名来自外部数据(服务端字段、路由表、JSON 配置)时,不能直接写常量,要用 fromName:
/// 服务端下发 {"icon": "bell_fill", "title": "通知"}
Icon(
OhosIcons.fromName(serverIconName),
size: 20,
)
fromName 的实现对"不存在的名字"零容忍——直接抛 ArgumentError:
static IconData fromName(String name) {
return info[name]?.icon ??
(throw ArgumentError.value(name, 'name', 'unknown symbol'));
}
所以生产代码里推荐"先查后取"的安全查询封装:
/// 安全版:名称不存在时返回 fallback,不抛异常
IconData iconByName(String name, {IconData fallback = OhosIcons.info_circle}) {
return OhosIcons.info[name]?.icon ?? fallback;
}
4.2 服务端驱动 / 路由配置
一个典型的"消息中心"配置模型,图标名作为普通字符串下发:
class NavItem {
const NavItem(this.title, this.iconName);
final String title;
final String iconName; // 服务端下发,如 'envelope'
}
final items = const [
NavItem('收件箱', 'envelope'),
NavItem('电话记录', 'phone'),
NavItem('星标', 'star_fill'),
NavItem('下载', 'download'),
];
// 列表渲染
ListTile(
leading: Icon(iconByName(item.iconName), size: 22),
title: Text(item.title),
trailing: const Icon(OhosIcons.chevron_right, size: 18),
)
4.3 兜底与灰度策略
数据驱动的图标必须设计兜底,否则一个脏数据就能让界面崩掉或出现方块:
- 默认兜底:所有查询都带 fallback(如
info_circle或questionmark_circle); - 白名单校验:数据入库/入缓存时先
OhosIcons.info.containsKey(name)过滤,脏数据在渲染前就被拦下; - 版本感知:
OhosIconMeta.supportVersion记录了每个图标的最低系统版本(本库 534 个图标中 525 个为HarmonyOS 5.0+,少数为5.1+/6.0/6.1),对低版本设备可用元数据判断是否需要降级替换。
注意:
fromName抛异常是特性不是缺陷——开发期尽早暴露配置错误。生产环境的稳健性由"安全查询 + 白名单"这一层保障,而不是改库的语义。
五、用法三:图标市场 / 选择器(遍历与筛选)
5.1 遍历全部图标
OhosIcons.values 返回全部 OhosIconMeta 的可迭代集合,"全量渲染"只需要一个 GridView:
GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 120, childAspectRatio: 1,
),
itemCount: OhosIcons.values.length,
itemBuilder: (context, index) {
final meta = OhosIcons.values.elementAt(index);
return Icon(meta.icon, size: 32);
},
)
5.2 按分类筛选
官方 17 个分类(系统UI、时间、编辑、通信、人物、交通出行、办公文件、连接……)可直接驱动筛选栏:
// 全部分类(已排序去重)
final categories = OhosIcons.categories; // 17 个
// 筛选"通信"分类
final communication = OhosIcons.values
.where((m) => m.categories.contains('通信'))
.toList();
注意 OhosIconMeta.categories 是复数列表:一个图标可以属于多个分类(如 wifi 同属 系统UI 与 连接),所以用 contains 而不是 ==。
5.3 搜索匹配(英文名 + 中文名双路)
图标市场最有用的功能是"按中文名搜图标"——这正是元数据里 label 的价值:
List<OhosIconMeta> filter(String query) {
final q = query.trim().toLowerCase();
return OhosIcons.values.where((m) {
if (q.isEmpty) return true;
return m.name.toLowerCase().contains(q) || m.label.contains(q);
}).toList()
..sort((a, b) => a.name.compareTo(b.name));
}
双路匹配的好处:设计师说"给我个飞行模式的图标",开发者输入"飞行模式"即可命中 airplane_fill,不需要先知道英文名。
提示:
OhosIcons.values每次访问都遍历info的 values,筛选/排序逻辑在数据量 534 时开销可忽略;若在极高频列表里重复调用,可先缓存List.of(OhosIcons.values)再过滤。
运行截图

相关资源:
- harmony_icons 仓库(AtomGit):oh-flutter/harmony_icons
- pub.dev 发布页:harmony_icons
- 鸿蒙社区 Flutter 分叉:CPF-Flutter/flutter_flutter
- 华为开发者官网 HarmonyOS Symbol:developer.huawei.com
- 参考对象 cupertino_icons:pub.dev/packages/cupertino_icons
- OpenHarmony 官网:openharmony.cn
- 开源鸿蒙跨平台社区:openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)