iOS IconFont 最佳实践 | 干掉图片资源,优雅地使用 Icon

7,985 阅读4分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

前言

作为大前端开发者一定经常使用很多小图标,使用小图标不可避免的要导入图片资源,图片资源又要考虑倍率、尺寸和颜色,总之体验不佳。为了解决这个问题 Iconfont 应运而生,不过原生使用体验还是不够好,本文目的就是优化开发体验。

什么是 IconFont

官方: 阿里妈妈 MUX 倾力打造的矢量图标管理、交流平台。 设计师将图标上传到 iconfont 平台,用户可以自定义下载多种格式的icon,平台也可将图标转换为字体,便于前端工程师自由调整与调用。

可喜的是 Iconfont 是免费的,且支持单色和多色。设计师可以开发自己的单色和多色图库,并以私有方式管理,供公司内部使用。

单色示例: image.png 多色示例: image.png

为什么要使用 IconFont

使用图片资源的痛点:

  • 在不同设备上图片倍率不同,需要导入 2 倍和 3 倍图
  • 图片资源比较大,不利于包大小控制
  • 同一图标不同颜色需要多张图
  • 图片资源管理起来容易显得混乱

IconFont 特点:

  • Icon 以自定义字体的形式定义在字体文件里
  • 字体是矢量的,这意味着无论 Icon 的 size 是 20 * 20 还是 2000 * 2000 都不会失真
  • 像使用任何系统提供的字体一样,字体可以设置任意颜色
  • 文件体积很小

通过以上分析很容易得出结论:使用 IconFont 利益极大,不使用 IconFont 危害极大

Iconfont 使用方式

iOS 端官方推荐使用方式:

image.png 我的第一感觉是有些怪怪的,可也确实合理,这么用又心有不甘。

痛点梳理:

  • 导入字体需要把字体相关文件导入工程,还要修改工程 info.plist 文件,这对多模块共享字体极不友好。更无法接受的是这基本无法对字体进行版本管理
  • 创建 Font 时需要硬编码字体名称,对我来说不太能接受
  • label.text 赋值时是 unicode 码,可读性极低,完全不能接受
  • 更多时候我们需要的是一张图片,使用 UILabel 显示一张图片不符合我们的常识和习惯

Iconfont 最佳实践

本着 IconFont 是个好东西,不能因为它当前存在的缺点而放弃它,应该尽量让它变得更加完美的宗旨,对使用方式进行了一些优化。

以上所有痛点都有办法解决:

  • 导入字体一定要把字体文件导入主工程并修改 info.plist 文件吗?并不是
  • 创建 Font 时需要硬编码字体名称吗?并不是
  • label.text 赋值时一定要是 unicode 码吗?是的,不过我们可以给它起个有意义的名字
  • 更多时候我们需要的是一张图片,可以把 Icon 转换为一张图片

问题分析透彻了,那就开始寻找条件是否满足。

  1. 字体是可以动态加载的,可以通过以下代码实现字体动态加载
  2. 字体名称硬编码显然可以轻松解决
  3. 观察 iconfont.json 文件,证明 label.text 赋值时可以给 unicode 码起个有意义的名称image.png
  4. 可以把 Icon 转换为一张图片

至此,以上所有痛点均已完美解决,下面是完整方案:

  1. 新建 CocoaPods 模块,用于多模块共享字体,命令pod lib create BBIconFont
  2. 新建 json2swift.py 脚本文件,内容如下:image.png
  3. 把下载来的 iconfont 文件夹拖入 Assets 目录 image.png
  4. 新增文件 UIFont+BBIconFont.swift,内容如下:image.png
  5. 新增文件 UIImage+BBIconFont.swift,内容如下:image.png
  6. 执行脚本 python json2swift.py
  7. 脚本成功执行后会生成文件 BBIconNames.swift,内容如下:image.png

业务代码中使用方式如下:

// 导入 BBIconFont 模块
import BBIconFont
​
// 获取 UIImage 对象,可以用于任意合适的地方
let image = UIImage.if_image(BBIconNames.add as NSString)
// 获取 UIImage 对象同时指定大小、颜色,可以用于任意合适的地方
let image = UIImage.if_image(BBIconNames.add as NSString, size: 16, color: .yellow)
​
// 字体方式使用
let lable = UILabel()
lable.font = UIFont.if_iconFont(16)
// 纯 Icon
lable.text = "后面是个 Iconfont 字符: \(BBIconNames.add)"
lable.textColor = .yellow
​

小结

通过我们的变通,最终可以像使用原生字体一样使用 IconFont,并能很好的对字体进行版本管理和共享。

最后给大家分享个观点:不要因为一个技术方案(大方向必须对,出发点是效能提升)当下的某些不完美而急于否定,而是应该首先思考能否让它变得更加完美。