简书地址

最近一直在写公司里的开源项目 JChat ,这里记录下其中优化过程。

什么是 Color 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,最终显示的是紫色:

null

这就是图层混合了。这种情况下,系统是需要消耗 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)                 

如何避免 Color Blended Layers

如果判断应用中是否有图层的混合呢,其实 Xcode 已经集成了这个功能,我们可以直接运行在模拟器里面后,通过 Debug -> Color Blended Layers 开启:

null

红色的部分说明存在图层混合,是需要我们去处理的地方式。

一般情况下,导致图层混合的可能主要有:

  1. opaque 为 false
  2. 图层存在透明度
  3. 图层没有默认颜色
  4. UI 图片资源本身就存在透明的通道

因为 UI 组件的 opaque 的默认值是 true,如果不是自己手动设置 false,一般都不是第一个原因导致的,看上面的 JChat 效果图,UILabel 中红色(图层混合)主要是因为 label 没有设置默认色导致的,所以我们需要设置下 label 的默认色:

usernameLabel.backgroundColor = .white

修改后我们再看效果:

null

从上面发现,如果 label 的 text 是中文的话,还是会发生图层混合,那是因为 label 的内容是中文时,实际渲染区域要大于 label 的大小,最外层多了一个 sublayer,这时我们可以通过

usernameLabel.layer.masksToBounds = true

来解决这个问题,我们再来看效果图:

null

上图中可以看到,其中一个资源图片发生了图层混合,这时明显就是 UI 的锅了,你就可以找你的 UI 妹子装逼了,如果你这觉得麻烦的话,自己打开 ps, 花上10秒自己修改下呗。突然又想起,以前的 UI 和自己扯了半小时,最后他花了两三分钟给我 p 了张图,然后搞定了-

小结

图层混合对性能的影响虽然不是特别大,但我们还是需要注意下的,积少成多,把每一步做好,才能更好地打造一款细滑般的应用。