最近一直在写公司里的开源项目 JChat ,这里记录下其中优化过程。
什么是 Blended Layers(图层混合)
这里举个例来说:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let v1 = UIView(frame: view.frame)
v1.backgroundColor = .red
let v2 = UIView(frame: view.frame)
v2.backgroundColor = .blue
v2.alpha = 0.5
view.addSubview(v1)
view.addSubview(v2)
}
}
在当前加页面上添加一个红色的 v1 和一个蓝色半透明的 v1,最终显示的是紫色:
这就是图层混合了。这种情况下,系统是需要消耗 GPU 资源来计算最终显示的颜色,rgba 的混合计算公式如下:
R(C) = (1-alpha)*R(B) + alpha*R(A)
G(C) = (1-alpha)*G(B) + alpha*G(A)
B(C) = (1-alpha)*B(B) + alpha*B(A)
如何避免 Blended Layers
如果判断应用中是否有图层的混合呢,其实 Xcode 已经集成了这个功能,我们可以直接运行在模拟器里面后,通过 Debug -> Color Blended Layers 开启:
红色的部分说明存在图层混合,是需要我们去处理的地方式。
一般情况下,导致图层混合的可能主要有:
- opaque 为 false
- 图层存在透明度
- 图层没有默认颜色
- UI 图片资源本身就存在透明的通道
因为 UI 组件的 opaque 的默认值是 true,如果不是自己手动设置 false,一般都不是第一个原因导致的,看上面的 JChat 效果图,UILabel 中红色(图层混合)主要是因为 label 没有设置默认色导致的,所以我们需要设置下 label 的默认色:
usernameLabel.backgroundColor = .white
修改后我们再看效果:
从上面发现,如果 label 的 text 是中文的话,还是会发生图层混合,那是因为 label 的内容是中文时,实际渲染区域要大于 label 的大小,最外层多了一个 sublayer,这时我们可以通过
usernameLabel.layer.masksToBounds = true
来解决这个问题,我们再来看效果图:
上图中可以看到,其中一个资源图片发生了图层混合,这时明显就是 UI 的锅了,你就可以找你的 UI 妹子装逼了,如果你这觉得麻烦的话,自己打开 ps, 花上10秒自己修改下呗。突然又想起,以前的 UI 和自己扯了半小时,最后他花了两三分钟给我 p 了张图,然后搞定了-
小结
图层混合对性能的影响虽然不是特别大,但我们还是需要注意下的,积少成多,把每一步做好,才能更好地打造一款细滑般的应用。