Icaro Icaro - 3 months ago 27
Swift Question

How to adjust a UILabel font size based on the height available to the label

I am using autolayout and text resizing with UILables and it works fine with width but not so much in the height.

If there is space for the text in the width but not in the height the text does not compress

Any Ideas how can I create constraints to do that? Or it that is not possible how can I find the minimum size of text that fits an rectangle?


You can set the font to automatically fill the size of a label, and optionally not go below a minimum font size. Just set adjustsFontSizeToFitWidth to YES. Check out the UILabel Class Reference if you need more information.

Although the boolean is called "adjustsFontSizeToWidth," it really means the largest size for the height of the label, that will stay on one line of the label (or however many lines you specify).

Subclassed UILabel and overrode layoutSubviews. Then each time the UILabel gets its size changed, the font size is recalculated:

import Foundation
import UIKit

class LabelWithAdaptiveTextHeight: UILabel {

override func layoutSubviews() {
    font = fontToFitHeight()

// Returns an UIFont that fits the new label's height.
private func fontToFitHeight() -> UIFont {

    var minFontSize: CGFloat = DISPLAY_FONT_MINIMUM // CGFloat 18
    var maxFontSize: CGFloat = DISPLAY_FONT_BIG     // CGFloat 67
    var fontSizeAverage: CGFloat = 0
    var textAndLabelHeightDiff: CGFloat = 0

    while (minFontSize <= maxFontSize) {
        fontSizeAverage = minFontSize + (maxFontSize - minFontSize) / 2

        if let labelText: NSString = text {
            let labelHeight = frame.size.height

            let testStringHeight = labelText.sizeWithAttributes(
                [NSFontAttributeName: font.fontWithSize(fontSizeAverage)]

            textAndLabelHeightDiff = labelHeight - testStringHeight

            if (fontSizeAverage == minFontSize || fontSizeAverage == maxFontSize) {
                if (textAndLabelHeightDiff < 0) {
                    return font.fontWithSize(fontSizeAverage - 1)
                return font.fontWithSize(fontSizeAverage)

            if (textAndLabelHeightDiff < 0) {
                maxFontSize = fontSizeAverage - 1

            } else if (textAndLabelHeightDiff > 0) {
                minFontSize = fontSizeAverage + 1

            } else {
                return font.fontWithSize(fontSizeAverage)
    return font.fontWithSize(fontSizeAverage)