HarmonyOS7 SVG 与图标:SymbolGlyph + 自定义 SVG 图标库搭建
·
前言
之前做项目图标都是切 PNG,1x 2x 3x 一堆文件塞得资源目录乱七八糟。后来发现 HarmonyOS7 的 SymbolGlyph 直接用系统图标,爽到飞起——直到产品说"这个图标系统里没有,要自定义的"。
好吧,自定义 SVG 图标这条路迟早得走。今天把从系统图标到自定义 SVG 的完整方案梳理一遍。
图标是 UI 里看着不起眼但特别重要的东西。一个 App 动辄几十上百个图标,管理不好就是灾难。HarmonyOS7 给了三条路:

- 系统 Symbol 图标 —— 零配置,拿来就用
- Svg 组件绘制 —— 纯代码画,适合简单图形
- SVG 资源文件 —— 设计师出图,开发引用,最常用
三条路各有利弊,往下看。
图标方案对比
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| SymbolGlyph | 系统标准图标 | 零配置、支持动效、自动适配字体粗细 | 只有系统预置图标,约433个 |
| Svg 组件绘制 | 简单几何图形 | 纯代码、动态可控 | 复杂图形代码量爆炸 |
| SVG 资源文件 | 自定义设计图标 | 任意图形、矢量不失真 | 需要管理资源文件 |
| PNG 图片 | 位图/特殊效果 | 兼容性好 | 多分辨率、文件大、不能动态着色 |
我的建议:系统图标能用的就用,不够的用 SVG 资源,别再用 PNG 了。
SymbolGlyph 系统图标
SymbolGlyph 是 HarmonyOS7 最省心的图标方案,直接引用系统图标库:

@Entry
@Component
struct SymbolGlyphDemo {
build() {
Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap, alignItems: ItemAlign.Center }) {
SymbolGlyph($r('sys.symbol.ohos_wifi'))
.fontSize(28)
.fontColor([Color.Black])
.renderingStrategy(SymbolRenderingStrategy.SINGLE)
SymbolGlyph($r('sys.symbol.ohos_folder_badge_plus'))
.fontSize(28)
.fontColor([Color.Blue])
.renderingStrategy(SymbolRenderingStrategy.SINGLE)
SymbolGlyph($r('sys.symbol.airplane_fill'))
.fontSize(28)
.fontColor([Color.Red])
.renderingStrategy(SymbolRenderingStrategy.SINGLE)
SymbolGlyph($r('sys.symbol.checkmark_circle'))
.fontSize(28)
.fontColor([Color.Black, Color.Green, Color.White])
.renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR)
}
.width('100%')
.padding(16)
.justifyContent(FlexAlign.SpaceAround)
}
}

关键代码讲解:
$r('sys.symbol.ohos_wifi')—— 引用系统图标,sys.symbol.是固定前缀,后面接图标标识名.fontSize(28)—— 图标大小跟字号一致,设 28 就是 28x28vp.fontColor([Color.Black])—— 颜色数组,单色渲染时只生效第一个renderingStrategy—— 渲染策略,决定了多颜色怎么分配到图层
渲染策略详解:
| 策略 | 说明 |
|---|---|
SINGLE |
单色,只用第一个颜色 |
MULTIPLE_OPACITY |
分层,一个颜色按不同透明度渲染各层 |
MULTIPLE_COLOR |
多色,每个图层独立设色 |
图标名称去哪找?华为开发者官网有完整的 Symbol 图标库,每个图标下面都标着标识名。
自定义 SVG 资源
系统图标不够用的时候,把设计师给的 SVG 文件放进资源目录:
resources/
base/
media/
icon_home.svg
icon_search.svg
icon_profile.svg
代码中引用:
Image($r('app.media.icon_home'))
.width(24)
.height(24)
.fillColor('#333333')
.objectFit(ImageFit.Contain)
关键代码讲解:
$r('app.media.icon_home')—— 引用 media 目录下的 SVG 文件.fillColor('#333333')—— SVG 专用属性,动态修改填充颜色,PNG 不支持这个.objectFit(ImageFit.Contain)—— 保持比例缩放
这里的
.fillColor()就是 SVG 比 PNG 强的地方——同一张 SVG 可以在不同场景复用不同颜色。
Svg 组件绘制
如果图标很简单(比如一个圆形、一个箭头),可以直接用 Svg 组件代码画:
@Entry
@Component
struct SvgDrawDemo {
build() {
Column({ space: 24 }) {
Shape() {
Circle()
.width(48)
.height(48)
.fill('#007DFF')
}
.width(48)
.height(48)
Shape() {
Path()
.commands('M12 4 L24 24 L0 24 Z')
.fill('#ff4444')
}
.width(24)
.height(24)
.viewBox({ x: 0, y: 0, width: 24, height: 24 })
Shape() {
Line()
.startPoint([0, 0])
.endPoint([24, 24])
.stroke(Color.Black)
.strokeWidth(2)
Line()
.startPoint([24, 0])
.endPoint([0, 24])
.stroke(Color.Black)
.strokeWidth(2)
}
.width(24)
.height(24)
}
.padding(24)
}
}
关键代码讲解:
Shape—— 所有绘制组件的容器,类似 SVG 的<svg>标签Circle()—— 画圆,width/height控制直径,fill填充颜色Path().commands()—— 自定义路径,M移动,L画线,Z闭合。M12 4 L24 24 L0 24 Z画了一个三角形viewBox()—— 定义坐标系,类似 SVG 的 viewBox 属性,确保路径在不同尺寸下比例正确Line()—— 画直线,startPoint/endPoint是起止坐标
复杂图形别硬画,代码维护成本太高。交给设计师出 SVG 文件才是正道。
图标库管理方案
图标一多就得有管理方案,不然东一个西一个,改起来要命。
推荐结构:
resources/
base/
media/
icons/
tab/
icon_home.svg
icon_search.svg
icon_message.svg
icon_profile.svg
action/
icon_add.svg
icon_delete.svg
icon_edit.svg
status/
icon_success.svg
icon_warning.svg
icon_error.svg
命名规范:
- 前缀按用途分类:
tab_、action_、status_ - 全小写+下划线,别用驼峰
- 一个图标一个文件,别把所有图标塞一个 SVG 里
动态着色
图标着色是高频需求——Tab 栏选中变色、暗黑模式变色、主题切换变色。SVG 的 .fillColor() 就是干这个的:
@Component
struct TabIconItem {
@Prop icon: Resource
@Prop isActive: boolean = false
build() {
Image(this.icon)
.width(24)
.height(24)
.fillColor(this.isActive ? '#007DFF' : '#999999')
.objectFit(ImageFit.Contain)
}
}
@Entry
@Component
struct DynamicColorDemo {
@State currentTab: number = 0
private tabs = [
{ icon: $r('app.media.icon_home'), label: '首页' },
{ icon: $r('app.media.icon_search'), label: '搜索' },
{ icon: $r('app.media.icon_profile'), label: '我的' }
]
build() {
Row() {
ForEach(this.tabs, (tab: Record<string, Resource | string>, index: number) => {
Column() {
TabIconItem({
icon: tab.icon as Resource,
isActive: this.currentTab === index
})
Text(tab.label as string)
.fontSize(12)
.fontColor(this.currentTab === index ? '#007DFF' : '#999999')
.margin({ top: 4 })
}
.layoutWeight(1)
.onClick(() => {
this.currentTab = index
})
})
}
.width('100%')
.height(56)
.padding({ top: 8, bottom: 8 })
}
}
关键代码讲解:
.fillColor(this.isActive ? '#007DFF' : '#999999')—— 核心! 选中蓝色,未选中灰色,一个属性搞定@Prop—— 子组件接收父组件传值,单向绑定够用- 同一张 SVG 文件,不同颜色渲染——这就是矢量的魅力
写在最后
图标方案就三句话:
- 能用 SymbolGlyph 就用,省心省力还带动效
- 自定义图标用 SVG 资源文件,fillColor 动态着色是杀手锏
- 别用 PNG,都 2026 了还切多分辨率图片,太古老了
图标管理也是工程问题,命名规范、目录结构提前定好,后面维护才不痛苦。
更多推荐

所有评论(0)