HarmonyOS7 SVG 与图标:SymbolGlyph + 自定义 SVG 图标库搭建
📅 2026/7/24 21:01:20
👁️ 阅读次数
📝 编程学习
文章目录
- 前言
- 图标方案对比
- SymbolGlyph 系统图标
- 自定义 SVG 资源
- 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@Componentstruct 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@Componentstruct 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()就是干这个的:
@Componentstruct TabIconItem{@Propicon:Resource@PropisActive:boolean=falsebuild(){Image(this.icon).width(24).height(24).fillColor(this.isActive?'#007DFF':'#999999').objectFit(ImageFit.Contain)}}@Entry@Componentstruct DynamicColorDemo{@StatecurrentTab:number=0privatetabs=[{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.iconasResource,isActive:this.currentTab===index})Text(tab.labelasstring).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 了还切多分辨率图片,太古老了
图标管理也是工程问题,命名规范、目录结构提前定好,后面维护才不痛苦。
编程学习
技术分享
实战经验