web-dev-qa-db-fra.com

Comment définir la taille de la police pour remplir la hauteur UILabel?

J'ai vu de nombreux exemples de modification de la taille d'un UILabel.

Voici ce que je voudrais faire: Changer la taille de la police pour que le texte soit aussi grand que possible dans la nouvelle hauteur.

Des indices?

47
wayneh

Edit: Découvrez La réponse géniale de Joel Fischer pour obtenir par programme la taille correcte!

Vous pouvez définir la police pour qu'elle remplisse automatiquement la taille d'une étiquette et ne descende pas éventuellement sous une taille de police minimale. Définissez simplement adjustsFontSizeToFitWidth sur YES. Consultez le Référence de la classe UILabel si vous avez besoin de plus d'informations.

Bien que le booléen soit appelé "adjustsFontSizeToFitWidth", il s'agit en réalité de la taille la plus grande pour la hauteur de l'étiquette, qui restera sur une ligne de l'étiquette (ou le nombre de lignes que vous spécifiez).

22
DGund

J'ai eu le même problème et, grâce à ce fil et à l'algorithme de Joel, j'ai pu le réparer. :-)

Ci-dessous, mon code dans Swift. Je suis dans iOS 8 + Autolayout.

Problème:

  1. Dépenses entrées utilisateur:

123 app

  1. Lorsque les utilisateurs appuient sur le bouton "cocher", un menu apparaît en partant du bas, en déplaçant tout en haut de l'écran (rétrécissement des éléments, y compris l'étiquette):

123 app

Après le correctif:

123 app

Quel est exactement ce que le designer avait à l'esprit ... :)

xScope app :)

J'ai sous-classé UILabel et surchargé layoutSubviews. Ensuite, chaque fois que la taille de UILabel change, la taille de la police est recalculée:

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

Voici comment je l'ai fait, puisque la réponse de DGund n'a pas fonctionné pour moi, elle correspond à la largeur, mais je voulais qu'elle s'adapte à la hauteur.

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

Cela prendra un nom de police, une taille (il ne doit pas nécessairement s'agir d'un UILabel, mais je l'ai toujours utilisé avec un UILabel), ainsi qu'une taille minimale (vous pouvez également utiliser une taille maximale, remplacez simplement le 256 par un le paramètre de taille maximale). Cela testera essentiellement chaque taille de police entre les tailles de police minimale et maximale et renverra celle qui se trouve à la hauteur cible ou juste en dessous de celle-ci.

L'utilisation est explicite, mais ressemble à ceci:

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

Vous pouvez également en faire une catégorie de méthode de classe sur UIFont (ce que j'ai fait).

EDIT: Sur suggestion, j'ai retiré la boucle for et ai passé un peu de temps à la rendre plus efficace avec une routine de recherche binaire. J'ai fait plusieurs vérifications pour être absolument sûr que la police de caractères correspondrait bien à l'étiquette. Lors des tests initiaux, cela semble fonctionner.

30
Joel Fischer

Il y a une solution plus simple. Ajoutez simplement les lignes ci-dessous et, comme par magie, l’étiquette ajuste la taille de la police à la hauteur de l’étiquette:

Swift 3:

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

adapter le texte en fonction de la hauteur de mon étiquette, j’ai adapté la méthode Joel à Swift 

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

et je l'utilise de cette façon:

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

Bonnes nouvelles,

Effectuer une recherche binaire est totalement inutile!

Vous avez seulement besoin d'itérer (plusieurs fois) à l'aide d'une recherche par ratio.

        guess = guess * ( desiredHeight / guessHeight )

Voici une solution complète IBDesignable complète.

Remarque: lorsque vous travaillez avec des concepteurs ou des typographes, vous devez définir le suivi/l’étirement des polices. (C’est absurde, n’incluez pas cela.) StyledLabelinclut également suivi/étirement.

StyledLabel.Swift

Il définit le suivi, l’étirement, ET la taille du point pour correspondre à la hauteur de la vue vue sur tous les périphériques.

Dans le storyboard: créez simplement le cadre de UILabel, à la hauteur souhaitée pour le texte - fin du récit!

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

Une ligne appelée dans viewWillAppear fait le tour:

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

Dans le storyboard, je règle toutes les hauteurs d'étiquette par rapport à la hauteur totale de la vue, ce qui permet à la taille de la police de s'adapter de manière dynamique à leur taille.

Notez que la taille de la police est en réalité 2/3 de la hauteur de l'étiquette. Si la police que vous utilisez a des queues qui descendent au-dessous de la ligne (comme dans y, g, q, p ou j), vous voudrez que la taille de la police corresponde à la hauteur de l'étiquette afin que ces queues ne soient pas hachées de. Les 2/3 fonctionnent bien pour Helvetica Neue, mais essayez d’autres ratios en fonction de la police que vous utilisez. Pour les polices sans texte, caractères numériques ou majuscules, un rapport 1: 1 peut suffire.

6
Edward Suczewski

Sur la base de l'excellente réponse de @ Conaaando, je l'ai mise à jour avec une version avec les paramètres IBDesignable inclus, ce qui permet de la modifier dans le générateur d'interface:

enter image description here

Et le 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

Cela emprunte beaucoup à la réponse de Joel Fischer. Sa réponse ne prend en compte que la hauteur de l'étiquette. J'ai apporté quelques modifications pour prendre en compte la largeur de l'étiquette (en fonction d'une chaîne d'entrée).

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

En combinant les réponses de @DGund et @Kashif, voici une solution simple pour l'IB:

 enter image description here

Cela correspond au texte en hauteur aussi bas que vous spécifiez dans le paramètre Autoshrink.

2
Denys Triasunov

Pour en savoir plus sur la réponse de @Joe Blow, voici une catégorie Objective-C UILabel+FitToHeight qui vous permet d'importer et de basculer facilement une adjustsFontSizeToFitHeight de la même manière que vous pouvez déjà 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]];
    }
}

Importez comme n'importe quelle autre catégorie ...

#import "UILabel+FitToHeight.h"

et utiliser comme suit ...

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

Il est intéressant de noter que ce still fonctionne avec [titleLabel setAdjustsFontSizeToFitWidth:YES];, de sorte que l’utilisation conjointe des deux est tout à fait possible.

1
Atlas Wegman

Pardonnez-moi si je me trompe, mais tout ce qui est mentionné ici est inutile. Définissez votre police à nouveau juste après le changement avec une nouvelle taille de police de votreLabel.height

Vous pouvez également rechercher une comparaison conditionnelle entre ces valeurs (yourLabel.height et fontSize) pour éviter les mises à jour inutiles.

Tout ce que vous devez faire c'est:

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

La réponse acceptée a un bug. La distance variable doit être un nombre à virgule flottante, sinon une taille de police trop grande peut être renvoyée. En outre, l'utilisation de "- (CGSize) sizeWithFont: (UIFont *) font;"; est obsolète. Voici le code avec ces 2 problèmes résolus.

+ (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

Variation rapide:

J'ai réussi à le faire avec une extension. Fonctionne très bien, la taille de police minimale est 5. Je soustrais 10 à la hauteur, je laisse donc une "marge" également, mais vous pouvez le supprimer ou le modifier. 

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

Mes excuses, si j'ai manqué quelque chose ici dans tout le texte.

J'ai suivi les suggestions @Crazyrems pour choisir automatiquement la police de caractères de l'étiquette. Cela met à l'échelle la police en fonction de la largeur, comme d'autres l'ont observé.

Ensuite, je viens de définir "Lignes" sur 0 dans la section de police de Xcode d'UILabel. Dans le code, cela devrait être numberOfLines. C'est tout.

Le mérite revient à @Mikrasya, qui a fait allusion à cette solution dans l'un des commentaires ci-dessus.

Testé sur Xcode 7.3 et iOS 9.3.2.

0
marco

Cela semblait fonctionner pour moi. J'ai sous-classé UILabel et, dans le layoutSubviews, j'ai vérifié la hauteur réelle et réglé la taille de la police en conséquence.

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

Construit à partir de réponse épique de Joel Fisher mais écrit comme extension 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))
    }

}

Utilisation:

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

Pour les étiquettes UIL qui redimensionnent proportionnellement pour les appareils plus grands/plus petits:

La solution la plus efficace pour moi a été de définir la taille de la police en fonction de la hauteur de l'étiquette +/- d'un facteur de correction. En supposant l'utilisation de contraintes de mise en page automatique, positionnez y y centre-vertical aligné au bas de la vue d'ensemble, multiplié par un rapport. De même, dans IB, contraignez la largeur de l'étiquette à une proportion de la largeur de l'écran.

Vous pouvez éventuellement verrouiller le rapport hauteur/largeur de l'étiquette avec une contrainte d'aspect. Toutefois, cela peut entraîner un écrêtage si vous ne maîtrisez pas correctement le calcul de la taille de la police. Le seul motif de verrouillage des proportions est si les positions des autres contrôles/vues sont relatives à cette étiquette. Cependant, je recommande fortement de placer de tels contrôles/vues par rapport à la hauteur/largeur du dessus afin qu'ils ne dépendent pas de cette étiquette.

Je comprends que ce n’est pas vraiment une solution encapsulée, mais elle m’a toujours causé le moins de chagrin. La seule autre solution qui se rapprochait utilisait les boucles while, mais dans mon cas, je ne pouvais pas gérer les délais imposés pour chaque appel système d'agencement/d'actualisation. 

0
ObjectiveTC