wake-up-neo.com

Wie kann man die Schriftgröße einstellen, um die Höhe von UILabel zu füllen?

Ich habe eine Reihe von Beispielen zur Änderung der Größe eines UILabels gesehen.

Folgendes möchte ich tun: Ändern Sie die Schriftgröße so, dass der Text innerhalb der neuen Höhe so groß wie möglich ist.

Irgendwelche Hinweise?

47
wayneh

Edit: Check out Joel Fischers tolle Antwort um programmgesteuert die richtige Größe zu erhalten!

Sie können festlegen, dass die Schriftart automatisch die Etikettengröße ausfüllt und optional eine Mindestschriftgröße nicht unterschreitet. Setzen Sie einfach adjustsFontSizeToFitWidth auf YES.. Überprüfen Sie die UILabel-Klassenreferenz , wenn Sie weitere Informationen benötigen.

Obwohl der Boolesche Wert "adjustsFontSizeToFitWidth" genannt wird, bedeutet dies wirklich die größte Größe für die Höhe der Beschriftung, die in einer Zeile der Beschriftung bleibt (oder wie viele Zeilen Sie angeben).

22
DGund

Ich hatte das gleiche Problem und dank dieses Threads und Joels Algorithmus konnte ich das Problem beheben. :-)

Unten ist mein Code in Swift. Ich bin in iOS 8 + Autolayout.

Problem:

  1. Benutzereingaben für Ausgaben:

123 app

  1. Wenn Benutzer auf die Schaltfläche "Prüfen" tippen, wird ein Menü von unten angezeigt, das alles an den oberen Rand des Bildschirms schiebt (das Zeug schrumpft, einschließlich des Etiketts):

123 app

Nach dem Update:

123 app

Genau das hatte der Designer vor Augen ... :)

xScope app :)

Ich habe UILabel subclassed und layoutSubviews überschrieben. Jedes Mal, wenn die Größe des UILabels geändert wird, wird die Schriftgröße neu berechnet:

//
//  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's text (it changes the label's font size)
 everytime its size (frame) is changed. This 'fits' the text to the new height, avoiding undesired text cropping.
 Kudos to this Stack Overflow 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'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

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

37
backslash-f

So habe ich es gemacht, da die Antwort von DGund für mich nicht funktionierte, sie auf die Breite passte, aber ich wollte, dass sie auf die Höhe passt.

+ (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];
}

Dies erfordert einen Schriftnamen, eine Größe (theoretisch muss es kein UILabel sein, aber ich habe ihn immer mit einem UILabel verwendet) und eine minimale Größe (Sie können auch eine maximale Größe verwenden, ersetzen Sie einfach die 256 durch der maximale Größenparameter). Dies testet im Wesentlichen jede Schriftgröße zwischen der minimalen und maximalen Schriftgröße und gibt die Schriftgröße zurück, die sich auf oder unterhalb der Zielhöhe befindet.

Die Verwendung ist selbsterklärend, sieht jedoch so aus:

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

Sie können dies auch zu einer Klassenmethodenkategorie auf UIFont machen (was ich auch getan habe).

BEARBEITEN: Auf Vorschlag habe ich die for-Schleife entfernt und etwas Zeit damit verbracht, sie mit einer binären Suchroutine effizienter zu gestalten. Ich habe mehrere Überprüfungen durchgeführt, um absolut sicherzugehen, dass die Schrift am Ende in das Etikett passt. Im ersten Test scheint es zu funktionieren.

30
Joel Fischer

Es gibt eine einfachere Lösung. Fügen Sie einfach unterhalb der Zeilen und magisch hinzu, das Etikett passt die Schriftgröße an die Etikettenhöhe an:

Swift 3:

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

um den Text an die Höhe meines Labels anzupassen, muss ich die Joel-Methode an Swift anpassen 

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

und ich benutze es so:

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

Gute Nachrichten,

Eine binäre Suche ist völlig überflüssig!

Sie müssen nur (einige Male) mithilfe einer Ratio-Suche iterieren.

        guess = guess * ( desiredHeight / guessHeight )

Hier ist eine vollständige IBDesignable-Lösung.

Hinweis: Wenn Sie mit Designern oder Typographen arbeiten, müssen Sie das Tracking/Stretching für Schriftarten festlegen. (Es ist absurd, dass Apple dies nicht enthält.) StyledLabelenthält auch Tracking/Stretching.

StyledLabel.Swift

Es legt Tracking, Stretching UND die Punktgröße an die view frame height aller Geräte fest.

Im Storyboard: Machen Sie einfach den Rahmen des UILabels, die Höhe, die der Text sein soll - Ende der Story!

// 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's 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's the simplest and fastest way to do that:

        guess = guess * ( desiredHeight / guessHeight )

That's 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
        }
    }
8
Fattie

Eine in viewWillAppear aufgerufene Zeile macht den Trick:

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

Im Storyboard habe ich alle meine Etikettenhöhen relativ zur Gesamthöhe der Ansicht festgelegt. Dadurch kann die Schriftgröße dynamisch an sie angepasst werden.

Beachten Sie, dass die Schriftgröße 2/3 der Etikettenhöhe beträgt. Wenn die Schriftart, die Sie verwenden, unter der Linie liegt (wie in y, g, q, p oder j), sollten Sie die Schriftgröße als Verhältnis der Etikettenhöhe festlegen, damit diese Enden nicht geschnitten werden aus. 2/3 funktioniert gut für Helvetica Neue, aber probieren Sie andere Verhältnisse abhängig von der verwendeten Schriftart. Für Schriften ohne Zahl, Zahl oder Text mit Großbuchstaben kann ein Verhältnis von 1: 1 ausreichen.

6

Basierend auf der großartigen Antwort von @ Conaaando habe ich sie auf eine Version mit IBDesignable-Parametern aktualisiert, die es ermöglicht, sie im Interface-Builder zu bearbeiten:

enter image description here

Und der Code:

//
//  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's 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)
    }
}
5
Antoine

Dies geht stark auf die Antwort von Joel Fischer zurück. Seine Antwort berücksichtigt nur die Etikettenhöhe. Ich habe einige Änderungen vorgenommen, um auch die Etikettenbreite zu berücksichtigen (bei Eingabe einer Zeichenfolge), die ich wollte:

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;
}
4
markckim

Die Antworten von @DGund und @Kashif kombinieren, hier eine einfache IB-Lösung:

 enter image description here

Der Text passt sich so an die Höhe an, wie Sie sie im Autoshrink-Parameter angegeben haben.

2
Denys Triasunov

Auf die Antwort von @Joe Blow eingegangen, ist hier eine Objective-C-Kategorie UILabel+FitToHeight, mit der Sie eine adjustsFontSizeToFitHeight auf einfache Weise importieren und umschalten können, ähnlich wie Sie bereits adjustsFontSizeToFitWidth können.

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]];
    }
}

Importieren Sie wie jede andere Kategorie ...

#import "UILabel+FitToHeight.h"

und wie folgt verwenden ...

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

Es ist erwähnenswert, dass still mit [titleLabel setAdjustsFontSizeToFitWidth:YES]; zusammenarbeitet, so dass die Verwendung der beiden in Verbindung möglich ist.

1
Atlas Wegman

Es gibt eine viel einfachere Möglichkeit, dies zu tun. Berechnen Sie einfach den Punkt pro Pixel des Bildschirms und multiplizieren Sie ihn mit der Höhe Ihres Etiketts, und Sie erhalten die gewünschte Schriftgröße.
Hier sind benutzerdefinierte Methoden dafür. Wählen Sie, was Sie wollen.

TYP 1. Hardodierte einzeilige Version:

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

TYP 2. Sauberere Version:

- (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;
}

Anwendungsbeispiele:

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

Verzeihen Sie, wenn ich falsch liege, aber alles, was hier erwähnt wird, ist unnötig. Setzen Sie Ihre Schriftart unmittelbar nach der Änderung erneut mit einer neuen fontSize von yourLabel.height

Sie können auch nach einem bedingten Vergleich zwischen diesen Werten (yourLabel.height und fontSize) suchen, um unnötige Aktualisierungen zu vermeiden.

Alles was Sie tun müssen, ist:

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

Die akzeptierte Antwort enthält einen Fehler. Der variable Abstand muss ein Float sein, oder er kann eine zu große Schriftgröße zurückgeben. Die Verwendung von "- (CGSize) sizeWithFont: (UIFont *) font;" ist veraltet. Hier ist der Code mit diesen 2 Problemen behoben.

+ (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];
}
0
user3174730

Schnelle Variation:

Ich habe es mit einer Erweiterung geschafft. Funktioniert gut, die minimale Schriftgröße ist 5. Ich subtrahiere 10 von der Höhe, daher lasse ich auch einen "Rand", aber Sie können ihn löschen oder ändern. 

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

}

0
ely87

Ich entschuldige mich, wenn ich hier im Text etwas verpasst habe.

Ich folgte @Crazyrems-Vorschlägen zum automatischen Schrumpfen der Schriftart des Labels. Dies skaliert die Schriftart basierend auf der Breite, wie von anderen beobachtet.

Dann habe ich 'Lines' im UILabel-Schriftbereich von Xcode auf 0 gesetzt. Im Code sollte dies numberOfLines sein. Das ist alles.

Dank geht an @Mikrasya, der in einem der obigen Kommentare auf diese Lösung hingewiesen hat.

Getestet mit Xcode 7.3 und iOS 9.3.2.

0
marco

Dies schien für mich zu funktionieren, ich habe UILabel untergeordnet und in den layoutSubviews die tatsächliche Höhe überprüft und die Schriftgröße entsprechend angepasst.

import UIKit

class HeightAdjustableLabel: UILabel {

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

Aufbauend auf Joel Fishers epischer Antwort aber als Swift 4 -Erweiterung geschrieben:

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

}

Verwendungszweck:

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)
0
NoodleOfDeath

Für UILabels, deren Größe für größere/kleinere Geräte proportional geändert wird:

Die effektivste Lösung für mich war es, die Punktgröße der Schrift auf ein Verhältnis der Höhe der Beschriftung +/- eines Anpassungsfaktors einzustellen. Unter der Annahme, dass Einschränkungen für das automatische Layout verwendet werden, positionieren Sie die Position um y vertikal am unteren Rand des Übersichtsobjekts, multipliziert mit einem Verhältnis. Auf ähnliche Weise beschränken Sie in IB die Breite des Etiketts auf einen Anteil der Bildschirmbreite.

Optional können Sie das Höhen-/Breitenverhältnis des Etiketts mit einer Seitenbeschränkung sperren. Dies kann jedoch zu Beschneidungen führen, wenn Sie die Berechnung der Punktgröße nicht richtig vornehmen. Der einzige Grund zum Sperren des Seitenverhältnisses ist, wenn die Positionen anderer Steuerelemente/Ansichten relativ zu dieser Bezeichnung sind. Ich empfehle jedoch dringend, solche Steuerelemente/Ansichten relativ zur Höhe/Breite des Superview zu platzieren, damit sie nicht von dieser Bezeichnung abhängig sind.

Ich verstehe, dass dies nicht gerade eine gekapselte Lösung ist, aber es hat mir immer die geringste Trauer gebracht. Die einzige andere Lösung, die nahe kam, nutzte While-Schleifen. In meinem Fall konnte ich jedoch nicht mit den Verzögerungen umgehen, die sie bei jedem Layout/Refresh-Systemaufruf verursachten. 

0
ObjectiveTC