在进行iOS应用开发的时候,经常会用到带有图标的按钮。
最近在更新账号小助手的时候,我发现xcode更新了一系列的系统图标,而且下拉一看都是十分规范而精美的,涵盖的内容也很丰富,这对于我们这样的独立的开发来说可以说是雪中送炭。
在网上搜一搜,不难发现这些系统图标是源自于2019WWDC大会的发布,并且苹果官方给了一套说明,甚至还有一个方便查找的mac app 传送门: Human Interface Guidelines - SF Symbols
而在具体的开发时,也还是能发现一些问题。
1. 最新的图标用起来固然爽,但是需要自己考虑向下兼容
可以看到,这个组件在iOS12或者更早时是无效的,我们如果在代码中用到相关的接口来获取图片对象时,同样也会告警处理低版本兼容问题。
代码语言:javascript复制UIImage( systemNamed: "doc.text" )
那我们如果为了兼容只能使用图片来替代了。 好在经过查找,我们发现 SF Symbols App是可以将矢量图标导出的,那我们就可以再使用其他工具生成对应的@x 图片文件了。
虽然还是回到了用图解决问题,但好在我们在做一些小部分的系统类Icon时候不用再费力去找素材了.
2. 使用图片降级方案时,按钮中图片大小成为烦恼
我们知道按钮中的图标,一般需要随着按钮的大小而自动调整,而在xcode中,我们将图片资源设置到对应的storyboard 或是 代码中的 imageView, UIButton.setImage 都会出现,图片保持了原图的大小这样的问题,并且还是被拉伸的状态。
在解决这个问题的时候,要解决几个问题 a. 保持图片的缩放比例 b. 图片颜色应该和文字、tintColor一致 c. 图片应该缩放到和正常的Symbol图标一致或接近
a 是比较好解决的,主要使用 contentMode 属性
b 需要同时设置RenderingMode 以及 tintColor
c 就比较麻烦了,最初的思路是设置UIButton下的imageView的size,frame,但是没有任何效果,网上查了很多在这个部分也是毫无收获,后来发现UIButton的图片机制完全是基于 imageEdgeInset 自动计算的。 希望自由控制按钮中图片的同学也可以注意了,使用imageEdgeInset设置图片基于按钮的上下左右距离,剩下来的空间的就是图片的最终size
不过只要思路弄清楚了,解决方案就不是问题。 下面是我的解题思路和方程式:
代码语言:javascript复制既然苹果是自动计算的,那我也自己也来自动计算一下图片的大小好了~
extension UIButton{
// 使用SF图标 size期望图标大小 为空自动计算最佳大小
func setSFIcon( name:String, size:CGFloat? = nil ){
/**
设置按钮中的图片图标 (只考虑图标在文字左侧)
1 拿到button大小
2 拿到label大小
3 拿到期望图标大小 / 计算最佳大小 ( 图标大小不能超过按钮 2/3高度, 只考虑正方形图标容器 )
4 计算间隙 ( 图标默认离文字要有 1/5 的距离 )
*/
let buttonSize = self.size
let labelSize = self.titleLabel?.size ?? CGSize(width: 0, height: 0)
var bestSize:CGFloat
if size != nil{
bestSize = size! > (buttonSize.height * 2) / 3 ? (buttonSize.height * 2) / 3 : size!
}else{
bestSize = 1.2 * labelSize.height
}
let left = (buttonSize.width - 1.2 * bestSize - labelSize.width) / 2
let right = (buttonSize.width - left - (bestSize * 1.2 ) )
let hInset = (buttonSize.height - bestSize) / 2
let icon = UIImage.SFIcon(name: name)?.withRenderingMode(.alwaysTemplate)
self.imageEdgeInsets = UIEdgeInsets(top: hInset, left: left, bottom: hInset, right: right)
self.imageView?.contentMode = .scaleAspectFit
self.setImage( icon, for: .normal)
self.tintColor = self.currentTitleColor
}
}
extension UIImage{
// 获取SF图标 早期系统使用图片资源
static func SFIcon( name:String ) -> UIImage?{
if #available(iOS 13.0, *) {
return UIImage( systemName: name )
} else {
return UIImage( named: name )
}
}
}
而在对应的ViewController中,调用就十分简单了
代码语言:javascript复制 copyButton.setSFIcon(name: "doc.on.doc", size: 18)