Как установить размер шрифта для заполнения высоты UILabel?

Я видел множество примеров для изменения размера UILabel.

Вот что я хотел бы сделать: Измените размер шрифта так, чтобы текст был как можно большим в пределах новой высоты.

Любые подсказки?

Ответ 1

Изменение: Проверьте Джоэл Фишер отличный ответ, чтобы программно получить правильный размер!

Вы можете настроить шрифт таким образом, чтобы он автоматически заполнял размер метки и при желании не опускался ниже минимального размера шрифта. Просто установите adjustsFontSizeToFitWidth в значение YES. Проверьте Справочник классов UILabel, если вам нужна дополнительная информация.

Хотя логическое значение называется "AdjusttsFontSizeToFitWidth", оно действительно означает наибольший размер для высоты метки, который будет оставаться на одной строке метки (или на любом количестве строк, которое вы укажете).

Ответ 2

У меня была такая же проблема, и благодаря этой теме и алгоритму Джоэля я мог ее исправить.: -)

Ниже мой код в Swift. Я нахожусь в iOS 8 + Autolayout.

Проблема:

  • Пользователь вводит затраты:

123 app

  1. Когда пользователи нажимают кнопку "проверить", снизу появляется меню, нажимая все на верхнюю часть экрана (сокращая материал, включая метку):

123 app

После исправления:

123 app

Это именно то, что имел в виду дизайнер...:)

xScope app :)

Я подклассифицировал UILabel и перегрузил layoutSubviews. Затем каждый раз, когда UILabel получает свой размер, размер шрифта пересчитывается:

//
//  LabelWithAdaptiveTextHeight.swift
//  123
//
//  Created by https://github.com/backslash-f on 12/19/14.
//

/*
 Designed with single-line UILabels in mind, this subclass 'resizes' the label text (it changes the label font size)
 everytime its size (frame) is changed. This 'fits' the text to the new height, avoiding undesired text cropping.
 Kudos to this Qaru thread: bit.ly/setFontSizeToFillUILabelHeight
*/

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

            // Abort if text happens to be nil
            guard text?.characters.count > 0 else {
              break
            }

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

Ответ 3

Вот как я это сделал, так как ответ DGund не работал у меня, он соответствовал ширине, но я хотел, чтобы он соответствовал высоте.

+ (UIFont *)findAdaptiveFontWithName:(NSString *)fontName forUILabelSize:(CGSize)labelSize withMinimumSize:(NSInteger)minSize
{
    UIFont *tempFont = nil;
    NSString *testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    NSInteger tempMin = minSize;
    NSInteger tempMax = 256;
    NSInteger mid = 0;
    NSInteger difference = 0;

    while (tempMin <= tempMax) {
        mid = tempMin + (tempMax - tempMin) / 2;
        tempFont = [UIFont fontWithName:fontName size:mid];
        difference = labelSize.height - [testString sizeWithFont:tempFont].height;

        if (mid == tempMin || mid == tempMax) {
            if (difference < 0) {
                return [UIFont fontWithName:fontName size:(mid - 1)];
            }

            return [UIFont fontWithName:fontName size:mid];
        }

        if (difference < 0) {
            tempMax = mid - 1;
        } else if (difference > 0) {
            tempMin = mid + 1;
        } else {
            return [UIFont fontWithName:fontName size:mid];
        }
    }

    return [UIFont fontWithName:fontName size:mid];
}

Это займет имя шрифта, размер (он не обязательно должен быть UILabel, теоретически, но я всегда использовал его с UILabel) и минимальный размер (вы также можете использовать максимальный размер, просто замените 256 с параметром максимального размера). Это, по существу, проверит каждый размер шрифта между минимальным и максимальным размерами шрифтов и вернет тот, который находится на уровне или чуть ниже целевой высоты.

Использование самоочевидно, но выглядит следующим образом:

self.myLabel.font = [self findAdaptiveFontWithName:@"HelveticaNeue-UltraLight" forUILabelSize:self.myLabel.frame.size withMinimumSize:30];

Вы также можете сделать эту категорию классов класса в UIFont (это то, что я сделал).

EDIT: по предложению я удалил цикл for и потратил немного времени, сделав его более эффективным с помощью процедуры бинарного поиска. Я сделал несколько проверок, чтобы абсолютно убедиться, что шрифт окажется в ярлыке. При первоначальном тестировании он работает.

Ответ 4

Существует более простое решение. Просто добавьте строки ниже и магически, метка регулирует свой размер шрифта, чтобы он соответствовал высоте метки:

SWIFT 3:

label.minimumScaleFactor = 0.1    //or whatever suits your need
label.adjustsFontSizeToFitWidth = true    
label.lineBreakMode = .byClipping
label.numberOfLines = 0

Ответ 5

чтобы адаптировать текст в соответствии с высотой моей метки. У меня есть метод Joel для быстрого

func optimisedfindAdaptiveFontWithName(fontName:String, label:UILabel!, minSize:CGFloat,maxSize:CGFloat) -> UIFont!
{

    var tempFont:UIFont
    var tempHeight:CGFloat
    var tempMax:CGFloat = maxSize
    var tempMin:CGFloat = minSize

    while (ceil(tempMin) != ceil(tempMax)){
        let testedSize = (tempMax + tempMin) / 2


        tempFont = UIFont(name:fontName, size:testedSize)
        let attributedString = NSAttributedString(string: label.text!, attributes: [NSFontAttributeName : tempFont])

        let textFrame = attributedString.boundingRectWithSize(CGSize(width: label.bounds.size.width, height: CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin , context: nil)

        let difference = label.frame.height - textFrame.height
        println("\(tempMin)-\(tempMax) - tested : \(testedSize) --> difference : \(difference)")
        if(difference > 0){
            tempMin = testedSize
        }else{
            tempMax = testedSize
        }
    }


    //returning the size -1 (to have enought space right and left)
    return UIFont(name: fontName, size: tempMin - 1)
}

и я использую его следующим образом:

myLabel.font = optimisedfindAdaptiveFontWithName("Helvetica", label: myLabel, minSize: 10, maxSize: 38)
    println("\(myLabel.font)")

Ответ 6

Хорошая новость,

Выполнение двоичного поиска совершенно не нужно!

Вам нужно только повторить (пару раз), используя поиск соотношения.

        guess = guess * ( desiredHeight / guessHeight )

Здесь полное полное решение IBDesignable.

Примечание. При работе с дизайнерами или типографами вам нужно будет установить отслеживание/растяжение для шрифтов. (Это абсурдно Apple не включает это.) StyledLabel также включает в себя отслеживание/растяжение.

StyledLabel.swift

Он устанавливает отслеживание, растяжение и устанавливает размер точки в соответствии с высотой кадра представления на всех устройствах.

В раскадровке: просто создайте рамку UILabel, высота которой вы хотите, чтобы текст был - конец истории!

// the call fontToFitHeight FINDS THE POINT SIZE TO "FILL TO HEIGHT".
// Just use autolayout to make the frame THE ACTUAL HEIGHT
// you want the type ON ANY DEVICE

// ADDITIONALLY you can set:
// the tracking (that the overall amount of space between all letters)
// and streching (actually squeeze or stretch the letters horizontally)

// Note: tracking and stretching IS SHOWN IN STORYBOARD LIVE
// WTT crazyrems http://stackoverflow.com/a/37300130/294884

import UIKit

@IBDesignable
class StyledLabel: UILabel
    {
    @IBInspectable var tracking:CGFloat = 0.8
    // values between about 0.7 to 1.3.  one means normal.

    @IBInspectable var stretching:CGFloat = -0.1
    // values between about -.5 to .5.  zero means normal.

    override func awakeFromNib()
        {
        tweak()
        }

    override func prepareForInterfaceBuilder()
        {
        tweak()
        }

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

    private func fontToFitHeight() -> UIFont
        {
/* Apple have failed to include a basic thing needed in handling text: fitting the text to the height. Here the simplest and fastest way to do that:

        guess = guess * ( desiredHeight / guessHeight )

That really all there is to it. The rest of the code in this routine is safeguards. Further, the routine iterates a couple of times, which is harmless, to take care of any theoretical bizarre nonlinear sizing issues with strange typefaces. */

        guard text?.characters.count > 0 else { return font }
        let desiredHeight:CGFloat = frame.size.height
        guard desiredHeight>1 else { return font }
        var guess:CGFloat
        var guessHeight:CGFloat

        print("searching for... ", desiredHeight)

        guess = font.pointSize
        if (guess>1&&guess<1000) { guess = 50 }

        guessHeight = sizeIf(guess)

        if (guessHeight==desiredHeight)
            {
            print("fluke, exact match within float math limits, up front")
            return font.fontWithSize(guess)
            }

        var iterations:Int = 4

/* It is incredibly unlikely you would need more than four iterations, "two" would rarely be needed. You could imagine some very strange glyph handling where the relationship is non-linear (or something weird): That is the only theoretical reason you'd ever need more than one or two iterations. Note that when you watch the output of the iterations, you'll sometimes/often see same or identical values for the result: this is correct and expected in a float iteration. */

        while(iterations>0)
            {
            guess = guess * ( desiredHeight / guessHeight )
            guessHeight = sizeIf(guess)

            if (guessHeight==desiredHeight)
                {
                print("unbelievable fluke, exact match within float math limits while iterating")
                return font.fontWithSize(guess)
                }

            iterations -= 1
            }

        print("done. Shame Apple doesn't do this for us!")
        return font.fontWithSize(guess)
        }

    private func sizeIf(pointSizeToTry:CGFloat)->(CGFloat)
        {
        let s:CGFloat = text!.sizeWithAttributes(
            [NSFontAttributeName: font.fontWithSize(pointSizeToTry)] )
            .height

        print("guessing .. ", pointSizeToTry, " .. " , s)
        return s
        }

    private func tweak()
        {
        let ats = NSMutableAttributedString(string: self.text!)
        let rg = NSRange(location: 0, length: self.text!.characters.count)

        ats.addAttribute(
            NSKernAttributeName, value:CGFloat(tracking), range:rg )

        ats.addAttribute(
            NSExpansionAttributeName, value:CGFloat(stretching), range:rg )

        self.attributedText = ats
        }
    }

Ответ 7

Одна строка, вызываемая в viewWillAppear, выполняет трюк:

testLabel.font = testLabel.font.fontWithSize(testLabel.frame.height * 2/3)

В раскадровке я установил все мои высоты ярлыков относительно общей высоты представления, и это позволяет динамически масштабировать размер шрифта с ними.

Обратите внимание, что размер шрифта на самом деле составляет 2/3 высоты метки. Если шрифт, который вы используете, имеет хвосты, которые опускаются ниже строки (как в y, g, q, p или j), вы хотите сделать размер шрифта равным высоте надписи, чтобы эти хвосты не были нарезаны выкл. 2/3 хорошо работает для Helvetica Neue, но попробуйте другие коэффициенты в зависимости от используемого шрифта. Для шрифтов без хвостов, цифр или текста всех шапок может быть достаточно отношения 1:1.

Ответ 8

Основываясь на замечательном ответе @Conaaando, я обновил его до версии с включенными IBDesignable параметрами, что позволяет редактировать его во всех конструкторах интерфейса:

enter image description here

И код:

//
//  TIFFitToHeightLabel.swift
//

import Foundation
import UIKit

@IBDesignable class TIFFitToHeightLabel: UILabel {

    @IBInspectable var minFontSize:CGFloat = 12 {
        didSet {
            font = fontToFitHeight()
        }
    }

    @IBInspectable var maxFontSize:CGFloat = 30 {
        didSet {
            font = fontToFitHeight()
        }
    }

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

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

        var minFontSize: CGFloat = self.minFontSize
        var maxFontSize: CGFloat = self.maxFontSize
        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)
    }
}

Ответ 9

Это сильно зависит от ответа Джоэла Фишера. Его ответ учитывает только высоту надписей - я внес некоторые изменения, чтобы учесть ширину метки (учитывая входную строку), которую я хотел:

typedef enum
{
    kDimensionHeight,
    kDimensionWidth,
} DimensionType;

@implementation UIFont (AdaptiveFont)

+ (UIFont *)_adaptiveFontWithName:(NSString *)fontName minSize:(NSInteger)minSize labelDimension:(CGFloat)labelDimension testString:(NSString *)testString dimension:(DimensionType)dimension
{
    UIFont *tempFont = nil;
    NSInteger tempMin = minSize;
    NSInteger tempMax = 256;
    NSInteger mid = 0;
    NSInteger difference = 0;
    CGFloat testStringDimension = 0.0;

    while (tempMin <= tempMax) {
        @autoreleasepool {
            mid = tempMin + (tempMax - tempMin) / 2;
            tempFont = [UIFont fontWithName:fontName size:mid];

            // determine dimension to test
            if (dimension == kDimensionHeight) {
                testStringDimension = [testString sizeWithFont:tempFont].height;
            } else {
                testStringDimension = [testString sizeWithFont:tempFont].width;
            }
            difference = labelDimension - testStringDimension;

            if (mid == tempMin || mid == tempMax) {
                if (difference < 0) {
                    return [UIFont fontWithName:fontName size:(mid - 1)];
                }
                return [UIFont fontWithName:fontName size:mid];
            }

            if (difference < 0) {
                tempMax = mid - 1;
            } else if (difference > 0) {
                tempMin = mid + 1;
            } else {
                return [UIFont fontWithName:fontName size:mid];
            }
        }
    }
    return [UIFont fontWithName:fontName size:mid];
}

+ (UIFont *)adaptiveFontWithName:(NSString *)fontName minSize:(NSInteger)minSize labelSize:(CGSize)labelSize string:(NSString *)string
{
    UIFont *adaptiveFont = nil;
    NSString *testString = nil;

    // get font, given a max height
    testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    UIFont *fontConstrainingHeight = [UIFont _adaptiveFontWithName:fontName minSize:minSize labelDimension:labelSize.height testString:testString dimension:kDimensionHeight];
    CGSize boundsConstrainingHeight = [string sizeWithFont:fontConstrainingHeight];
    CGSize boundsConstrainingWidth = CGSizeZero;

    // if WIDTH is fine (while constraining HEIGHT), return that font
    if (boundsConstrainingHeight.width <= labelSize.width) {
        adaptiveFont = fontConstrainingHeight;
    } else {
        // get font, given a max width
        // i.e., fontConstrainingWidth
        testString = string;
        adaptiveFont = [UIFont _adaptiveFontWithName:fontName minSize:minSize labelDimension:labelSize.width testString:testString dimension:kDimensionWidth];

        // TEST comparison
        boundsConstrainingWidth = [string sizeWithFont:adaptiveFont];
    }
    return adaptiveFont;
}

Ответ 10

Объединив ответы @DGund и @Kashif, здесь простое решение IB:

введите описание изображения здесь

Это соответствует тексту по высоте, как указано в параметре Autoshrink.

Ответ 11

Существует намного упрощенный способ сделать это. Просто вычислите точку на пиксель экрана и умножьте его на высоту своего ярлыка, и вы получите размер шрифта, который вы хотите удалить.
Для этого используются специальные методы. Выберите все, что хотите.

ТИП 1. Однострочная версия:

- (CGFloat) fontSizeFromHeight:(CGFloat)height
{
     return ceilf(height * (10.0 / [@"Tg" sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:10.0]}].height));
}

ТИП 2. Чистая версия:

- (CGFloat)fontSizeFromHeight:(CGFloat)height
{
    static CGFloat const testFontSize = 12.0;
    static NSString * const testText = @"TestString";
    UIFont *testFont = [UIFont systemFontOfSize:testFontSize];
    CGFloat pixelHeight = [testText sizeWithAttributes:@{NSFontAttributeName:testFont}].height;
    CGFloat pointPerPixel = testFontSize / pixelHeight;
    CGFloat desiredFontSize = ceilf(height * pointPerPixel);
    return desiredFontSize;
}

Примеры использования:

myLabel.font = [UIFont systemFontOfSize:[self fontSizeFromHeight:myLabel.frame.size.height]];  
myLabel.font = [myLabel.font fontWithSize:[self fontSizeFromHeight:myLabel.frame.size.height]];

Ответ 12

Расширение на @Joe Blow отвечает: Objective-C category UILabel+FitToHeight, который позволяет вам легко импортировать и переключать adjustsFontSizeToFitHeight так же, как вы уже можете adjustsFontSizeToFitWidth.

UILabel + FitToHeight.h

#import <UIKit/UIKit.h>

@interface UILabel (FitToHeight)

@property (nonatomic, assign) BOOL adjustsFontSizeToFitHeight;

@end

UILabel + FitToHeight.m

#import "UILabel+FitToHeight.h"

#import <objc/runtime.h>

@implementation UILabel (FitToHeight)

-(BOOL)adjustsFontSizeToFitHeight {
    NSNumber *number = objc_getAssociatedObject(self, @selector(adjustsFontSizeToFitHeight));
    return [number boolValue];
}

-(void)setAdjustsFontSizeToFitHeight:(BOOL)adjustsFontSizeToFitHeight {
    NSNumber *number = [NSNumber numberWithBool:adjustsFontSizeToFitHeight];
    objc_setAssociatedObject(self, @selector(adjustsFontSizeToFitHeight), number, OBJC_ASSOCIATION_ASSIGN);
}

-(UIFont *)fontToFitHeight {
    float desiredHeight = [self frame].size.height;
    float guess;
    float guessHeight;

    guess = [[self font] pointSize];
    guessHeight = [self sizeIf:guess];
    if(guessHeight == desiredHeight) {
        return [[self font] fontWithSize:guess];
    }

    int attempts = 4;
    while(attempts > 0) {
        guess = guess * (desiredHeight / guessHeight);
        guessHeight = [self sizeIf:guess];

        if(guessHeight == desiredHeight) {
            return [[self font] fontWithSize:guess];
        }

        attempts--;
    }

    return [[self font] fontWithSize:guess];
}

-(float)sizeIf:(float)sizeToTry {
    CGSize size = [[self text] sizeWithAttributes:@{ NSFontAttributeName : [[self font] fontWithSize:sizeToTry] }];
    return size.height;
}

-(void)layoutSubviews {
    [super layoutSubviews];

    if([self adjustsFontSizeToFitHeight]) {
        [self setFont:[self fontToFitHeight]];
    }
}

Импорт, как и любая другая категория...

#import "UILabel+FitToHeight.h"

и используйте следующее:

UILabel *titleLabel = [[UILabel alloc] init];
[titleLabel setAdjustsFontSizeToFitHeight:YES];
[titleLabel setAdjustsFontSizeToFitWidth:YES];

Стоит отметить, что это все еще работает с [titleLabel setAdjustsFontSizeToFitWidth:YES];, поэтому использование двух в соединении вполне возможно.

Ответ 13

Для UILabels, которые пропорционально изменяют размер для более крупных/меньших устройств:

Наиболее эффективным решением для меня было установить размер шрифта в размере отношения высоты надписи +/- корректирующего коэффициента. Предполагая использование ограничений автоматической компоновки, поместите его вертикально-вертикальным центром в нижнее положение надзора, умноженное на коэффициент. Аналогично в IB, ограничивайте ширину метки до доли ширины экрана.

Необязательно, вы можете заблокировать отношение высоты/ширины метки с ограничением на аспект, однако это может привести к отсечению, если вы не получили правильное вычисление размера шрифта. Единственная причина блокировки соотношения сторон - это позиция других элементов управления/представлений относительно этой метки. Однако я настоятельно рекомендую разместить такие элементы управления/представления относительно высоты/ширины супервизора, чтобы они не зависели от этой метки.

Я понимаю, что это не совсем инкапсулированное решение, но оно постоянно вызывало у меня наименьшее количество горя. Единственное другое решение, которое пришло близко, использовало циклы while, однако в моем случае я не мог справиться с задержками, которые они налагали для каждого вызова компоновки/обновления.

Ответ 14

Мои извинения, если я пропустил что-то здесь во всем тексте.

Я выполнил @Crazyrems предложения для автовоспроизведения шрифта метки. Это масштабирует шрифт по ширине, как это наблюдали другие.

Затем я просто установил 'Lines' в 0 в секции шрифта UILabel Xcode. В коде это должно быть numberOfLines. Это все.

Кредит отправляется @Mikrasya, который намекнул на это решение в одном из комментариев выше.

Протестировано на Xcode 7.3 и iOS 9.3.2.

Ответ 15

Изменение SWIFT:

Мне удалось сделать это с расширением. Работает нормально, минимальный размер шрифта - 5. Я вычитаю 10 из высоты, поэтому оставляю также "margin", но вы можете удалить его или изменить.

extension UILabel {

//Finds and sets a font size that matches the height of the frame. 
//Use in case the font size is epic huge and you need to resize it.
func resizeToFitHeight(){
    var currentfontSize = font.pointSize
    let minFontsize = CGFloat(5)
    let constrainedSize = CGSizeMake(frame.width, CGFloat.max)

    while (currentfontSize >= minFontsize){
        let newFont = font.fontWithSize(currentfontSize)
        let attributedText: NSAttributedString = NSAttributedString(string: text!, attributes: [NSFontAttributeName: newFont])
        let rect: CGRect = attributedText.boundingRectWithSize(constrainedSize, options: .UsesLineFragmentOrigin, context: nil)
        let size: CGSize = rect.size

        if (size.height < frame.height - 10) {
            font = newFont
            break;
        }

        currentfontSize--
    }

    //In case the text is too long, we still show something... ;)
    if (currentfontSize == minFontsize){
        font = font.fontWithSize(currentfontSize)
    }
}

}

Ответ 16

Простите меня, если я ошибаюсь, но все, что упоминается здесь, не нужно. Снова установите шрифт сразу после изменения с помощью нового fontSize вашего объекта yourLabel.height

Вы также можете проверить условное сравнение этих значений (yourLabel.height и fontSize), чтобы предотвратить ненужные обновления.

Все, что вам нужно сделать, это:

[yourLabel setFont:[UIFont fontWithName:@"*your fontname*" size:yourLabel.frame.size.height]];

Ответ 17

Построение эпического ответа Джоэла Фишера, но написанного как расширение Swift 4:

extension String {

    /// Attempts to return the font specified by name of the appropriate point
    /// size for this string to fit within a particular container size and
    /// constrained to a lower and upper bound point size.
    /// - parameter name: of the font.
    /// - parameter containerSize: that this string should fit inside.
    /// - parameter lowerBound: minimum allowable point size of this font.
    /// - parameter upperBound: maximum allowable point size of this font.
    /// - returns: the font specified by name of the appropriate point
    /// size for this string to fit within a particular container size and
    /// constrained to a lower and upper bound point size; 'nil' if no such
    /// font exists.
    public func font(named name: String,
                     toFit containerSize: CGSize,
                     noSmallerThan lowerBound: CGFloat = 1.0,
                     noLargerThan upperBound: CGFloat = 256.0) -> UIFont? {
        let lowerBound = lowerBound > upperBound ? upperBound : lowerBound
        let mid = lowerBound + (upperBound - lowerBound) / 2
        guard let tempFont = UIFont(name: name, size: mid) else { return nil }
        let difference = containerSize.height -
            self.size(withAttributes:
                [NSAttributedStringKey.font : tempFont]).height
        if mid == lowerBound || mid == upperBound {
            return UIFont(name: name, size: difference < 0 ? mid - 1 : mid)
        }
        return difference < 0 ? font(named: name,
                                     toFit: containerSize,
                                     noSmallerThan: mid,
                                     noLargerThan: mid - 1) :
            (difference > 0 ? font(named: name,
                                   toFit: containerSize,
                                   noSmallerThan: mid,
                                   noLargerThan: mid - 1) :
                UIFont(name: name, size: mid))
    }

    /// Returns the system font of the appropriate point size for this string
    /// to fit within a particular container size and constrained to a lower
    /// and upper bound point size.
    /// - parameter containerSize: that this string should fit inside.
    /// - parameter lowerBound: minimum allowable point size of this font.
    /// - parameter upperBound: maximum allowable point size of this font.
    /// - returns: the system font of the appropriate point size for this string
    /// to fit within a particular container size and constrained to a lower
    /// and upper bound point size.
    public func systemFont(toFit containerSize: CGSize,
                           noSmallerThan lowerBound: CGFloat = 1.0,
                           noLargerThan upperBound: CGFloat = 256.0) -> UIFont {
        let lowerBound = lowerBound > upperBound ? upperBound : lowerBound
        let mid = lowerBound + (upperBound - lowerBound) / 2
        let tempFont = UIFont.systemFont(ofSize: mid)
        let difference = containerSize.height -
            self.size(withAttributes:
                [NSAttributedStringKey.font : tempFont]).height
        if mid == lowerBound || mid == upperBound {
            return UIFont.systemFont(ofSize: difference < 0 ? mid - 1 : mid)
        }
        return difference < 0 ? systemFont(toFit: containerSize,
                                           noSmallerThan: mid,
                                           noLargerThan: mid - 1) :
            (difference > 0 ? systemFont(toFit: containerSize,
                                         noSmallerThan: mid,
                                         noLargerThan: mid - 1) :
                UIFont.systemFont(ofSize: mid))
    }

}

Использование:

let font = "Test string".font(named: "Courier New",
                              toFit: CGSize(width: 150.0, height: 30.0),
                              noSmallerThan: 12.0,
                              noLargerThan: 20.0)
let sysfont = "Test string".systemFont(toFit: CGSize(width: 150.0, height: 30.0),
                                       noSmallerThan: 12.0,
                                       noLargerThan: 20.0)

Ответ 18

В принятом ответе есть ошибка. Переменное расстояние должно быть плавающим, или оно может вернуть слишком большой размер шрифта. Также использование шрифта "- (CGSize) sizeWithFont: (UIFont *);" устарела. Здесь код с этими 2 проблемами исправлен.

+ (UIFont *)findAdaptiveFontWithName:(NSString *)fontName forUILabelSize:(float)maxHeight withMaxFontSize:(int)maxFontSize
{
    UIFont *tempFont = nil;
    NSString *testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    NSInteger tempMin = 0;
    NSInteger tempMax = maxFontSize;
    NSInteger mid = 0;
    float difference = 0;

    while (tempMin <= tempMax) {
        mid = tempMin + (tempMax - tempMin) / 2;
        tempFont = [UIFont fontWithName:fontName size:mid];

        UILabel* dummyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        dummyLabel.text = testString;
        dummyLabel.font = tempFont;
        [dummyLabel sizeToFit];

        difference = maxHeight - dummyLabel.bounds.size.height;

        if (mid == tempMin || mid == tempMax) {
            if (difference < 0) {
                return [UIFont fontWithName:fontName size:(mid - 1)];
            }

            return [UIFont fontWithName:fontName size:mid];
        }

        if (difference < 0) {
            tempMax = mid - 1;
        } else if (difference > 0) {
            tempMin = mid + 1;
        } else {
            return [UIFont fontWithName:fontName size:mid];
        }
    }

    return [UIFont fontWithName:fontName size:mid];
}

Ответ 19

Мне показалось, что это работает, я подкласс UILabel и в layoutSubviews я проверил фактическую высоту и соответственно изменил размер шрифта.

import UIKit

class HeightAdjustableLabel: UILabel {

    override func layoutSubviews() {
        super.layoutSubviews()
        if frame.height < font.pointSize + 2 {
            font = font.withSize(frame.height - 2)
        }
    }
}

Ответ 20

Я сделал макрос, чтобы сделать это для вас

///Scales FontSize up (or down) until the text fits within the height of the label, will not auto-update, must be called any time text is updated. Label Frame must be set prior to calling
#define scaleFontSizeToFillHeight(__label) {\
__label.font = [UIFont fontWithName:__label.font.fontName size:__label.frame.size.height*2.0f];\
UIFont *__currentFont = __label.font;\
CGFloat __originalFontSize = __currentFont.pointSize;\
CGSize __currentSize = [__label.text sizeWithAttributes:@{NSFontAttributeName : __currentFont}];\
while (__currentSize.height > __label.frame.size.height && __currentFont.pointSize > (__originalFontSize * __label.minimumScaleFactor)) {\
__currentFont = [__currentFont fontWithSize:__currentFont.pointSize - 1];\
__currentSize = [__label.text sizeWithAttributes:@{NSFontAttributeName : __currentFont}];\
}\
__label.font = __currentFont;\
}

Ответ 21

Да, перейдите к построителю интерфейса (ваш .xib файл) и перейдите на третью вкладку справа в инспекторе атрибутов, и вы можете установить размер шрифта там!