0
votes

It seems when adjustsFontSizeToFitWidth = true and you have numberOfLines set to a constant (I used 2), when Auto Layout calculates the size of the UILabel it uses the font size that's set on the label's font property, instead of the font size that it's adjusted to when its laid out. When I increase the font size, the height of the label's frame grows, but the displayed font size stays the same (since it's limited to 2 lines and its sides are pinned to its superview).

My hacky solution is to somehow find the biggest font size that will completely fill the width of the label's frame while still fitting on 2 lines, and then set the font size to that so the auto shrinking doesn't occur.

Is there a way to tell Auto Layout to shrink the text before calculating size?

1

1 Answers

0
votes

I've seen similar questions before, and the basic answer appears to be:

No, Autolayout will not change the height of a UILabel with fixed number of lines and adjustsFontSizeToFitWidth = true.

One workaround:

  • Do not set adjustsFontSizeToFitWidth = true for your label
  • Create a second, hidden label with the same constraints, and do set adjustsFontSizeToFitWidth = true and set a .minimumScaleFactor
  • Calculate the actual, system adjusted font size of the hidden label and use that value to set the font size of the visible label

Example:

@IBOutlet var myLabelHidden: UILabel!
@IBOutlet var myLabelVisible: UILabel!

func getActualFontSize(_ forLabel: UILabel) -> CGFloat {

    guard let labelText = forLabel.text else {
        return 0.0
    }
    let labelContext = NSStringDrawingContext()
    labelContext.minimumScaleFactor = forLabel.minimumScaleFactor
    let attString = NSAttributedString(string: labelText, attributes: [NSAttributedStringKey.font: forLabel.font])
    _ = attString.boundingRect(with: forLabel.frame.size,
                                   options: [.usesFontLeading, .usesLineFragmentOrigin],
                                   context: labelContext)
    let actualFontSize = forLabel.font.pointSize * labelContext.actualScaleFactor
    return actualFontSize

}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    var fs = getActualFontSize(myLabelHidden)
    // font sizing seems to be most accurate when
    // rounded down to a single decimal place
    fs = (fs * 10.0).rounded(.down) / 10.0
    myLabelVisible.font = myLabelVisible.font.withSize(fs)

}

override func viewDidLoad() {
    super.viewDidLoad()

    myLabelHidden.text = "This should adjust the font size to fit."
    myLabelVisible.text = myLabelHidden.text

    myLabelHidden.isHidden = true

}