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

I use auto-detect and resize text with UILables and it works fine with width, but not that high.

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

Any ideas how I can create constraints for this? Or is this not possible, how can I find the minimum text size that fits the rectangle?

+3


source to share


3 answers


You can set the font to automatically fill the size of the label and optionally not fit the minimum font size. Just set the FontSizeToFitWidth parameter to YES. Check out the link to the UILabel class if you need more information.

Although the logical name is called "adjustsFontSizeToWidth", it does mean the largest size for the height of the label that will remain on one label line (or, however many lines are specified).



Subclasses UILabel and overrode layoutSubviews. Then every time the UILabel gets its size, the font size is recalculated:

import Foundation
import UIKit

class LabelWithAdaptiveTextHeight: UILabel {

override func layoutSubviews() {
    super.layoutSubviews()
    font = fontToFitHeight()
}

// Returns an UIFont that fits the new label 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)]
            ).height

            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)
}
}

      

+6


source


Swift 3.0 is for everyone who comes here.

Many thanks to @tymac for the original answer.



Really helped me not to worry about text sizes when my apps were versatile.

import UIKit
import Foundation

class LabelWithAdaptiveTextHeight: UILabel {

    override func layoutSubviews() {
        super.layoutSubviews()
        font = fontToFitHeight()
    }

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

        var minFontSize: CGFloat = 20
        var maxFontSize: CGFloat = 250
        var fontSizeAverage: CGFloat = 0
        var textAndLabelHeightDiff: CGFloat = 0

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

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

                let testStringHeight = labelText.size(attributes: [NSFontAttributeName: font.withSize(fontSizeAverage)]).height

                textAndLabelHeightDiff = labelHeight - testStringHeight

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

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

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

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

      

+5


source


Below is an example of doing a tymac Objective-C query for anyone interested.

(I was in a bit of a rush and didn't have time to fix the lowercase Gs, Js, Ps and Qs, so I quickly subtracted two from the average text size in the calculate function, sorry).

#import "LabelWithAdaptiveTextHeight.h"

#define DISPLAY_FONT_MINIMUM 6
#define DISPLAY_FONT_MAXIMUM 50

@interface LabelWithAdaptiveTextHeight ()

@end

@implementation LabelWithAdaptiveTextHeight

- (UIFont*)fontToFitHeight {
    float minimumFontSize = DISPLAY_FONT_MINIMUM;
    float maximumFontSize = DISPLAY_FONT_MAXIMUM;
    float fontSizeAverage = 0;
    float textAndLabelHeightDifference = 0;

    while(minimumFontSize <= maximumFontSize){
        fontSizeAverage = minimumFontSize + (maximumFontSize - minimumFontSize) / 2;
        if(self.text){
            float labelHeight = self.frame.size.height;
            float testStringHeight = [self.text sizeWithAttributes:@{
                                                                NSFontAttributeName: [self.font fontWithSize:fontSizeAverage]
                                                                }].height;

            textAndLabelHeightDifference = labelHeight - testStringHeight;

            if(fontSizeAverage == minimumFontSize || fontSizeAverage == maximumFontSize){
                return [self.font fontWithSize:fontSizeAverage- (textAndLabelHeightDifference < 0)];
            }
            if(textAndLabelHeightDifference < 0){
                maximumFontSize = fontSizeAverage - 1;
            }
            else if(textAndLabelHeightDifference > 0){
                minimumFontSize = fontSizeAverage + 1;
            }
            else{
                return [self.font fontWithSize:fontSizeAverage];
            }
        }
        else {
            break; //Prevent infinite loop
        }
    }
    return [self.font fontWithSize:fontSizeAverage-2];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.font = [self fontToFitHeight];
}

@end

      

+1


source







All Articles