如何修复iOS 11上的UILabel intrinsicContentSize

时间:2018-01-11 16:36:09

标签: ios iphone uikit uilabel

在iOS 11上,由于标签显然误报了其内部的内容大小,我们的许多布局都在破碎。

当UILabel被包装在另一个尝试实现intrinsicContentSize的视图中时,该错误似乎表现得更糟。像这样(简化和人为的例子):

class LabelView: UIView {

    let label = UILabel()

    override init(frame: CGRect) {

        super.init(frame: frame)

        self.setup()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setup() {

        self.label.textColor = .black
        self.label.backgroundColor = .green
        self.backgroundColor = .red
        self.label.numberOfLines = 0
        self.addSubview(self.label)

        self.label.translatesAutoresizingMaskIntoConstraints = false
        self.label.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        self.label.trailingAnchor.constraint(lessThanOrEqualTo: self.trailingAnchor).isActive = true
        self.label.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        self.label.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
    }

    override var intrinsicContentSize: CGSize {

        let size = self.label.intrinsicContentSize

        print(size)

        return size
    }
}

UILabel的intrinsicContentSize非常独特,看起来像:(width: 1073741824.0, height: 20.5)。这会导致布局周期为视图的包装器提供太多空间。

仅当从XCode 9编译iOS 11时才会发生这种情况。在iOS 10 SDK(在XCode 8上)上编译的iOS 11上运行时。

在XCode 8(iOS 10)上,视图的呈现方式如下:

enter image description here

在XCode 9(iOS 11)上,视图呈现如下:

XCode 9 rendering

完整的操场代码证明此问题的要点是here

我已经为此提交了一个雷达,至少有一个问题的解决方案(见下面的答案)。我想知道是否有其他人遇到过这个问题,或者有其他方法可能会尝试。

1 个答案:

答案 0 :(得分:0)

因此,通过在操场上进行实验,我能够提出一个解决方案,包括测试极大的内在内容大小。

我注意到所有行为不端的UIL用户都有numberOfLines==0preferredMaxLayoutWidth=0。在随后的布局过程中,UIKit将preferredMaxLayoutWidth设置为非零值,可能是迭代到标签的正确高度。因此,第一个问题是尝试在numberOfLines时暂时设置(self.label.numberOfLines == 0 && self.label.preferredMaxLayoutWidth == 0)

我还注意到所有将这两个属性都设为0的UILabel不一定行为异常。 (即逆是不正确的)。所以这个修复工作有效,但在某些时候不必要地修改了标签。它还有一个小错误,当标签的文本包含\n个换行符时,行数应设置为字符串中的行数,而不是1。

我来到的最终解决方案是更加hacky,但是特别关注UILabel的行为不端,然后只是踢它...

override var intrinsicContentSize: CGSize {

    guard super.intrinsicContentSize.width > 1000000000.0 else {

        return super.intrinsicContentSize
    }

    var count = 0

    if let text = self.text {

        text.enumerateLines {(_, _) in
            count += 1
        }

    } else {

        count = 1
    }

    let oldNumberOfLines = self.numberOfLines

    self.numberOfLines = count
    let size = super.intrinsicContentSize

    self.numberOfLines = oldNumberOfLines

    return size
}

您可以将此作为要点here找到。

相关问题