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

时间:2015-05-05 19:48:34

标签: ios autolayout uilabel 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))

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

enter image description here

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

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

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

在这里玩test project

2 个答案:

答案 0 :(得分:1)

看看你加入的测试项目。

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

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

如果你使用90这样的较小尺寸,它可以很好地工作,因为它适合不到450。

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

如果你删除了高度限制它可以正常工作,但它的高度是> 450。

所以你的问题只是测试字体太大而不能达到450高度。

可能的解决方案:

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

基本上你使用:

CGFloat actualFontSize;
[label.text sizeWithFont:label.font
             minFontSize:label.minimumFontSize
          actualFontSize:&actualFontSize
                forWidth:label.bounds.size.width
           lineBreakMode:label.lineBreakMode];

这已弃用,但这并不意味着您暂时无法使用它。你需要将它转换为swift。

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

可能的解决方案更新:

我搜索了sizeWithFont的快速等价物,并且有很多文章,但我没有看到哪些文章替换了上述功能的版本。

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

答案 1 :(得分:1)

我看了一下你的项目,我可能已经找到了解决问题的方法。

我在标签设置中添加了以下内容:

label.minimumScaleFactor = 0.5

这是我改变后视图的样子: enter image description here

标签顶部没有更多间距。

希望这可以帮助您解决问题!让我知道它是怎么回事。