在UILabel中更改字体时,UILabel大小计算错误

Ben*_*ard 6 uilabel ios autolayout nslayoutconstraint

我正在向具有以下布局要求的视图添加UILabel:

  • 标签应居中
  • 标签的最大字体大小应为100磅,但应缩小以适应.它不应该截断.
  • 标签的高度不应超过450磅.
  • 另一个视图将直接位于标签下方.

我的标签的属性布局约束似乎充分描述了这一点:

let label = UILabel()
label.backgroundColor = UIColor.yellowColor()
label.font = UIFont.systemFontOfSize(100)
label.numberOfLines = 0
label.textAlignment = .Center
label.adjustsFontSizeToFitWidth = true
label.text = "What's Brewing in PET/CT: CT and MR Emphasis"
label.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(label)

view.addConstraint(NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .Left, relatedBy: .Equal, toItem: view, attribute: .Left, multiplier: 1, constant: 60))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .Right, relatedBy: .Equal, toItem: view, attribute: .Right, multiplier: 1, constant: -60))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .Height, relatedBy: .LessThanOrEqual, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 450))
Run Code Online (Sandbox Code Playgroud)

但是,我发现如果内容较长,如下所示,标签会显示一些意外的边距:

在此输入图像描述

这是不可接受的,因为标签正上方或下方的任何视图都会有间隙.

根据下面的讨论,我的工作原理是布局引擎根据字体大小100计算大小,而不考虑内容较长时的后续缩放.

如何满足上面列出的布局要求(理想情况下不使用任何弃用的方法)?

这是一个可以玩的测试项目.

Ror*_*nel 1

查看您善意添加的测试项目。

问题是你设置的字体太大(100pt),无法满足450点的高度。您已经设置了label.adjustsFontSizeToFitWidth = true导致它尝试通过使用较小的字体来尽可能适合它的设置。

因此,当您将字体设置为 100 时,它会根据截断的原始文本调整文本区域的大小,然后通过更改字体以适应宽度来压缩文本区域。压缩后,顶部和底部会留下间隙,因为尺寸是基于原始字体的。

如果您使用较小的尺寸(例如 90),则效果很好,因为它适合小于 450。

如果删除 adjustmentFontSizeToWith 它可以正常工作并填充空间,但它会截断文本。

如果删除高度限制,它可以正常工作,但其高度会> 450。

所以你的问题很简单,测试字体对于 450 高度来说太大了。

可能的解决方案:

使用此处的答案询问标签所需的字体大小:How to get UILabel (UITextView) auto adjustment font size?

基本上你使用:

CGFloat actualFontSize;
[label.text sizeWithFont:label.font
             minFontSize:label.minimumFontSize
          actualFontSize:&actualFontSize
                forWidth:label.bounds.size.width
           lineBreakMode:label.lineBreakMode];
Run Code Online (Sandbox Code Playgroud)

这已被弃用,但这并不意味着您现在不能使用它。您需要将其转换为 swift。

调用此方法,如果字体大小小于原始大小,则将标签中的字体设置为较小的大小。理论上这应该给你一个完美的配合,因为它应该调整到你设置的新字体大小。

可能的解决方案更新:

我搜索了 的 swift 等效项sizeWithFont,并且有很多文章,但我看不到哪些文章取代了上面提到的函数的版本。

一个稍微低效的解决方案是在您addSubview发布的测试项目中的代码之前添加以下内容(请原谅我的快速)。它基本上向后搜索字体大小,直到字体符合已知的限制。这显然可以提高效率,但它表明,如果您在布局之前计算正确的字体,那么它将完全适合 450.0 高度。

在您的项目中对此进行了测试,文本在最初不适合 450.0 的情况下完美适合

    // The current font size and name
    var fontSize:CGFloat = 120
    let fontName:String = "AvenirNext-Regular"

    // The size to fit is the frame width with 60 margin each size and height
    // of 450
    let fitSize:CGSize = CGSize(width:view.frame.width-120.0,height:450)
    var newSize:CGSize

    do{
        // Create the trial font
        label.font = UIFont(name: fontName, size: fontSize)

        // Calculate the size this would need based on the fitSize we want
        newSize = label.sizeThatFits(fitSize)

        // Make the font size smaller for next time around.
        fontSize-=0.5
    } while (newSize.height >= 450)

    println("Font size had to be reduced to \(fontSize)")

    view.addSubview(label)
Run Code Online (Sandbox Code Playgroud)