目前开发环境下,在 web 端用到 iconfont 相对较多,而因为各种原因很少移动端很少采用 iconfont;
但因其诸多优势的存在,很多公司团队一直保留着 iconfont 的图标方案;
最近彩色图标字体出现,更是解决了 iconfont 存在的硬伤,本文将探究 图标字体 代替 svg / nX 的可行性,以及它们之间的用法对比。
其实想到这个话题,是最近公司项目进行了一次包体积优化,其中一项优化就是针对图标资源的。而最近又关注到,iconfont 已经支持彩色图标字体,就用一个 Demo 做了一下对比,发现相比之下,包含几十个图标的字体包比一个 svg 图标资源的体积还要小,于是就 iconfont 方案探究了一番。
一、前言
图标在互联网上几乎每个网站和应用程序中都占有重要地位,自从它的出现,就一直存在着图标集之争。
以往,开发人员只能依靠图像格式来满足他们的需求。但使用图像作为图标在渲染质量和分辨率方面的性能非常差。现在开发人员有两种选择:图标字体与 SVG 图标(可缩放矢量图形)。
而两者之间谁是最优选择?其实开发社区一直都在争论一种比另一种的优点。然而,近些年人们对 SVG 图标格式有了普遍的喜爱。SVG 图标可确保较好的性能、更高的可访问性标准、高渲染质量、无与伦比的灵活性和广泛的自定义。
但?iconfont 真的不是一种好选择吗?答案肯定是否定的!从某种意义上说,它反而更具有优势。
二、当前的赢家:svg 图标
我们先来看看 svg 图标的使用的现状和存在的不足。
现状
iOS:
首先对于 iOS 来说,想要使用 svg 是相对比较困难的,一般都是借助第三方库方案。虽然官方提供的也有支持的方案(Symbol Image),但使用起来整个流程都比较复杂(从制作图标到开发),请版本支持也不太友好。所以目前大多数 iOS 开发中仍然采用的是 2x/3x/.. 的方案。
Android:
而 Android 平台对 svg 的支持,目前来说已经相对比较成熟,从导入工具(AS资源目录右键 > new > Vector Asset 即可将 svg 转换成 Vector 资源),到开发使用,到最后的效果都比较完善。详见官方使用教程:《添加多密度矢量图形》
同时可以自行配置需要的 icon 尺寸,打包时会自动将 svg 生成对应尺寸的 png 图片。
defaultConfig {
...
// minSdkVersion 19 (5.0)
vectorDrawables.generatedDensities('xhdpi', 'xxhdpi', 'xxxhdpi')
// minSdkVersion > 19
// vectorDrawables.useSupportLibrary = true
}
复制代码
下面是(minSdk = 19)默认打包时情况:
从上图也能看出,对于 svg 图标来说,它所占用的体积绝不单单是一个 vector 资源文件。
不足
具体的使用,这里不再展开说明。这里只提一下,svg 图标使用时值得注意的一些问题。
首先 svg 图标可以分为,彩色图标和单色图标,其中对于彩色图标来说,不建议图标中存在渐变色的设计,会有意想不到的问题。
在布局文件中使用,单色图标可以通过着色器 app:tint="@android:color/white"
来改变图标的颜色。
动态改变 svg 颜色问题
var vectorDrawableCompat = VectorDrawableCompat.create(resources, R.drawable.ic_mysql, theme)
vectorDrawableCompat?.setTint(resources.getColor(android.R.color.black))
ivIcon.setImageDrawable(vectorDrawableCompat)
复制代码
可以通过以上代码动态改变 svg 图标的颜色,但是当在其他场景中使用相同图标资源的时候。会发现图标颜色会和你前面动态设置的颜色相同。
这是因为使用时这个图标资源被加载到内存中。当资源被修改的时其实是修改内存的资源。这个时候该资源内存没有被覆盖或者回收。当再次使用的时候,保留了我们上一次修改的状态。
三、潜力选手:iconfont
在开始之前,先总结一下 iconfont 的优缺点。
优点:
- 可以在各种分辨率下使用,缩放不会模糊,告别 iOS 中 2x/3x 以及未来 nx 的问题;
- 一套资源可在 web、iOS、Android 等多个平台使用,大统一了展示和使用方法;
- 一定程度上减小文件体积;
- 可以通过字体颜色值集的变换,来达到一键换肤,一键更换图标整体颜色,图片复用;
- 可以添加一些视觉效果如:阴影、旋转、透明度
- 后期维护成本很低
缺点:
- 图标制作成本高
- 更新成本高,最好以比较规范的项目方式来维护
- 开发中定位不准(文本本身显示的原因)
对于 iconfont 来说,优势有很多,但缺点主要集中在制作成本,同时需要良好的项目图标维护方式,因为每次更新时是对整个图标字体集的更新。
推荐借助类似阿里巴巴图标库中的项目管理来维护整个项目的图标。也可以通过SVG 在线转 iconfont。
使用
iconfont 的使用方式其实很简单,无论是哪个端(Android|iOS|Web)都是通过文本的方式直接显示,需要注意的是:文本需要设置成图标对应的字符;将显示文本的字体设置成你的 iconfont 字体。
具体的使用流程,这里不再详解了,大家应该也都接触过,不会的请自行搜索教程。
通过 iconfont.cn 将项目中的图标下载到本地时,一般是一个压缩包,里面存放了生成的字体文件,和图标对应字符的网页文件,还有图标名称和字符对应的 iconfont.json 文件。
如下图:
在开发中,为了方便使用会把 iconfont 中所有的图标对应的字符列举成文本资源(strings.xml);同时这样在每次更新字体文件时,如果有图标遗漏,也能很方便的发现。
我是通过写了一个 jar 脚本,通过读取下载的字体压缩包中的 iconfont.json 文件,将字体中包含所有图标字符转换成开发时需要的文本资源。
iconfont2strings.jar 下载地址:img.shedoor.net/blog/iconfo…
彩色 iconfont
一直以来,iconfont 最大的禁锢就是图标只支持单色的。现在这个问题在 iconfont.cn 上得到了突破,使字体支持彩色字体,而整个使用流程上和单色 iconfont 没有任何差别。
唯一需要注意的是,在下载之前需要将项目设置成支持彩色字体格式,如下图:
关于彩色 iconfont 更详细的讲解可以查看:
《iconfont 支持全新的彩色字体图标》
测试效果
写了一个小 Demo 简单测试了一下,通过设置文本大小,字体颜色(针对单色)就可以改变图标真的不是其他图标方案能够比拟的。
显示效果如下:
彩色 iconfont 具体代码:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:fontFamily="@font/iconfont_color"
android:text="@string/icon_color_chick"
android:textColor="@android:color/white"
android:textSize="30dp" />
复制代码
注意上面代码,针对彩色 iconfont 在开发中这里有一点需要注意:
- 无法通过设置字体颜色来对其做改变的;
- 但仍需要给其设置一个字体颜色(随意什么颜色都可以),如果不设置,显示时颜色会偏浅,目前这个原因不详;
四、方案总结
iconfont 方案最大的优势体现在:能够在各个端对图标做使用的统一;另一方面能够有效的在一定程度上优化包体积。
这里在使用上做一下具体的实施总结:
- 通过类似 iconfont.cn 平台的项目管理做图标管理;
- 每个版本图标的变更,建议采用全量替换整个字体文件和对应字符资源文件;// 可以防止图标的遗漏和重复
- 由于我们的项目大多都使用组件化(或依赖库)的形式,我们可以直接在不同的组件都引入全量的字体文件和全量的字体字符资源文件;// 相同名字的字体文件、和相同命名的字符串,在生成 apk 时只会保留一个
- 由于每个版本并不是每个组件的 iconfont 字体都会更新,所以要保证壳工程 appshell 内的字体文件是最新的;
- 单色图标、彩色图标分开采用两种字体管理;// 彩色字体格式不支持改变颜色
- 对于单色图标的控制,可以直接对文本颜色、大小、阴影等进行控制;
- 对于彩色图标的颜色变换,可以采用同一个图标不同颜色不同字符,在变换时,可以直接变换文本显示的字符就可以了;
如果采用 iconfont 你对包体积的优化还不满足,你还可以更近一步,将 iconfont 字体作为网络字体使用,详细可查看:
Android 开发文档《可下载字体》