【问题标题】:UILabel size calculated incorrectly when changing font in UILabel更改 UILabel 中的字体时,UILabel 大小计算不正确
【发布时间】:2015-07-15 17:13:49
【问题描述】:

我正在将 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))

但是,我发现对于像下面这样较长的内容,标签会显示一些意想不到的边距:

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

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

我怎样才能满足上面列出的布局要求(最好不使用任何已弃用的方法)?

这里有一个test project 可以玩。

【问题讨论】:

  • 您似乎将高度设置为 = 0 而不是
  • 是的,这是必需的(我将更新我的问题以提及它) - 我不希望标签的长度超过 450,但它可以而且应该尽可能短。我的理解是拥抱优先是为了解决这个问题。
  • 当你设置文本/字体时,你可以尝试调用[label sizeToFit];。不是快人。我猜应该是label.sizeToFit()
  • 谢谢,但我已经尝试过了(以及 setNeedsUpdateConstraints 和 setNeedsLayout)
  • 当您使用 .XXXXThanOrEqual 约束时,使用具有 .Equal 和较低优先级的另一个约束通常会有所帮助,因此您可以告诉布局管理器在哪个方向进行缩放。因此,在您的情况下,请尝试将高度等于 0 并将优先级设置为低

标签: ios autolayout uilabel nslayoutconstraint


【解决方案1】:

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

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

label.minimumScaleFactor = 0.5

这是我更改后视图的样子:

标签顶部不再有间距。

希望这可以帮助您解决问题!告诉我进展如何。

【讨论】:

  • 谢谢,但我认为这只是这个特定字符串的幸运突破 - 例如,尝试将标签文本换成 "Current Controversies, Problems, and Techniques in Nuclear Medicine 2014 - Part I" 并且问题仍然存在。不过,对我来说很奇怪,设置minimumScaleFactor 会将布局从三行更改为四行。如果有的话,由于字体大小只能通过添加这个来减小(或保持不变),我希望标签能够跨越更少或相同数量的行 - 而不是更多。也许这种帮助会为某人指明正确的方向。
  • 是的,你是对的。但是,如果您更改 minimumFontScale 的值,它也会起作用。但是,很明显这不应该是这样的。我在UILabel 类中发现了这个,同时查看了您的问题var adjustsFontSizeToFitWidth: Bool // default is NO // deprecated - hand tune by using NSKernAttributeName to affect tracking // NOTE: deprecated - use minimumScaleFactor. default is 0.0,所以它可能是框架中的一个错误
【解决方案2】:

看看你好心添加的测试项目。

问题是你设置的字体太大(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 的 swift 等效项,并且有很多文章,但我看不到哪个替换了上述函数的版本。

一个稍微低效的解决方案是在您发布的测试项目中的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)

【讨论】:

  • 但是标签的文本是可变的,当短 100 点是合适的大小。似乎这就是adjustsFontSizeToFitWidth 的全部意义所在? “拟合”计算不应该与 adjustFontSize 值一起工作,而不是假设截断?将字体大小更改为 90 将为我需要容纳的较长字符串重现相同的问题。
  • 您希望如此,但似乎并非如此。我认为这是因为它在视觉上缩小它以适应宽度而不是高度。我用可能的解决方案更新了我的答案。我认为让它工作的唯一方法是调整字体大小,当它对 450 来说太大时。
  • 刚刚看到您使用可能的解决方案进行的编辑,谢谢。我会试试看。还考虑将行数设置为 3 或 4 而不是 0,并删除高度限制。
  • @BenPackard 是的,您实际上只有三个选项:缩放字体以使其符合描述,放松高度限制或限制行数。限制行会导致它截断文本,但这可能不是一件好事。
  • @BenPackard 发布了另一个更新,其中包含可以工作的快速代码。在您的项目中对其进行了测试。在添加子视图之前添加代码。可以提高效率,但表明一般方法可行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 2013-09-24
  • 1970-01-01
相关资源
最近更新 更多