如何在 iOS 11 上修复 UILabel intrinsicContentSize

Posted

技术标签:

【中文标题】如何在 iOS 11 上修复 UILabel intrinsicContentSize【英文标题】:How to fix UILabel intrinsicContentSize on iOS 11 【发布时间】:2018-01-11 16:36:08 【问题描述】:

ios 11 上,由于标签明显错误地报告了它们的 intrinsicContentSize,我们的许多布局都被破坏了。

当 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 11 上运行时,在 iOS 10 SDK 上编译(在 XCode 8 上)。

在 XCode 8 (iOS 10) 上,视图正确呈现如下:

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

带有完整 Playground 代码的 Gist 是 here。

我已经为此提交了一份雷达,并且至少有一个解决该问题的方法(请参阅下面的答案)。我想知道是否有其他人遇到过这个问题或有其他方法可以尝试。

【问题讨论】:

【参考方案1】:

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

我注意到所有行为不端的 UILabel 都有 numberOfLines==0preferredMaxLayoutWidth=0。在随后的布局过程中,UIKit 将 preferredMaxLayoutWidth 设置为非零值,大概是为了迭代到标签的正确高度。所以第一个解决方法是尝试在(self.label.numberOfLines == 0 && self.label.preferredMaxLayoutWidth == 0) 时临时设置numberOfLines

我还注意到,所有将这两个属性设为 0 的 UILabel 不一定会出现异常行为。 (即反过来不正确)。所以这个修复工作,但在某些时候不必要地修改了标签。它还有一个小bug,当标签的文本包含\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

您可以将其作为 Gist here 找到。

【讨论】:

我为这个问题找到了一个不那么老套的解决方案。修复是设置 UILabel 的preferredMaxLayoutWidth。我将它设置为这样的屏幕宽度:preferredMaxLayoutWidth = UIScreen.main.bounds.width 我自己认为这可能是一个更老套的解决方案 经过 6 小时的奋斗,您只是一个救生员。 Hacky macky,它只是工作:thumbsup:@sam 这也有同样的效果:***.com/a/26181894/956701 很高兴它帮助了@ergunkocak 另一种解决方案看起来不错,但我不知道如果不提前知道宽度是否会起作用,如我上面的示例所示

以上是关于如何在 iOS 11 上修复 UILabel intrinsicContentSize的主要内容,如果未能解决你的问题,请参考以下文章

ios:如何在背景图像上添加 uiLabel?

如何在 iOS 上使用 Sign In with Google 修复“用户取消了登录流程。”?

只需要修复 UIButton 和 UILabel 的自动布局问题

如何在 iOS 8 上修复横向导航栏项目的高度?

UILabel 未在 iOS8 中显示子视图

iOS 约束:如何给 UILabel 高度约束优先级