UIStackView 背景颜色的探究

2,290 阅读2分钟

这里每天分享一个 iOS 的新知识,快来关注我吧

UIStackView

UIStackView 是在 iOS 9 中推出的一个新的视图类。用于在横向或纵向中布置视图集合的简化界面。随着最低版本的提高,目前在日常的开发中使用 UIStackView 已经越来越多了。

设置背景颜色无效的问题

最近发现一个小问题,给 UIStackView 设置背景颜色之后,在 iOS 13 及以下的设备中无效。

UIStackView 虽然继承自 UIView,但它不是 UIView 的普通子类。在 iOS 13 之前,它一直都是一个 “非渲染子类”,也就是不参与渲染,只用作布局。因此当你设置其 backgroundColor 后没有任何效果。

通常的做法是在 UIStackView 中插入一个新的 UIView,来作为背景,比如下边这个扩展的实现。

extension UIStackView {
    func addBackground(color: UIColor) {
        let subView = UIView(frame: bounds)
        subView.backgroundColor = color
        subView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        insertSubview(subView, at: 0)
    }
}

使用的时候可以这样写:

stackView.addBackground(color: .red)

iOS 14 对此做了优化,在 iOS 14 上是可以正常通过 backgroundColor 设置背景颜色的,因此这个扩展中可以加入对版本的判断:

extension UIStackView {
    func addBackground(color: UIColor) {
       if #available(iOS 14.0, *) {
            backgroundColor = color
        } else {
            let subView = UIView(frame: bounds)
            subView.backgroundColor = color
            subView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            insertSubview(subView, at: 0)
        }
    }
}

iOS 14 做了什么

接下来探究一下为什么在 iOS 14 中就可以正常设置背景颜色了。

一个主要的改动是在 iOS 14 中, UIStackView 的内部 layer 已从原来的 CATransformLayer 更改为使用 CALayer

CATransformLayer 可以用来创建 3D 图层层次结构,与 CALayer 不同的地方在于,它不会把自己渲染出来。这就意味着它会忽略 backgroundColor 等属性。

证明这一点很简单,我们只需要在 iOS 13 和 iOS 14 的控制台打印一下 UIStackView 对象:

在 iOS 13 上:

(lldb) po rootStackView
<UIStackView: 0x7fdc0270b3c0; frame = (0 0; 0 0);
layer = <CATransformLayer: 0x600002de3e40>>

可以看到其对应的 layer 对象是 CATransformLayer

在 iOS 14 上:

(lldb) po rootStackView
<UIStackView: 0x7fa253f0bdc0; frame = (0 0; 0 0);
layer = <CALayer: 0x600003339440>>

可以看到其对应的 layer 对象是 CALayer

由于 iOS 14 上用的是 CALayer,所以我们可以像操作正常的 UIView 一样对 UIStackView 进行设置了。但是如果你的应用兼容 iOS 14 以下系统,还需要做好兼容性适配。

本文同步自微信公众号 “iOS新知”,每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!