65 votes

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

J'ai vu plusieurs exemples pour changer la taille d'un UILabel.

Voici ce que j'aimerais faire : Modifier la taille de la police pour que le texte soit aussi grand que possible dans la nouvelle hauteur.

Des indications ?

1 votes

Je viens de réaliser que réaliser une recherche binaire ou autre est totalement inutile. Vous n'avez qu'à itérer (quelques fois) en utilisant une recherche de ratio. C'est tout simple. Je vais coller le code complet dans ma réponse.

1 votes

.. solution complète pour 2016 stackoverflow.com/a/37277874/294884 Code très simple.

3voto

Just Shadow Points 2077

Il existe une façon beaucoup plus simple de le faire. Il suffit de calculer le nombre de points par pixel de l'écran et de le multiplier par la hauteur de votre libellé, et vous obtiendrez la taille de police souhaitée.
Voici des méthodes personnalisées pour cela. Choisissez ce que vous voulez.

TYPE 1. Version à une seule ligne codée en dur :

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

TYPE 2. Version plus propre :

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

Exemples d'utilisation :

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

2voto

Atlas Wegman Points 541

En développant la réponse de @Joe Blow, voici une catégorie Objective-C UILabel+FitToHeight qui vous permet d'importer facilement et de basculer un adjustsFontSizeToFitHeight à l'instar de ce que vous pouvez déjà faire avec adjustsFontSizeToFitWidth.

UILabel+FitToHeight.h

#import 

@interface UILabel (FitToHeight)

@property (nonatomic, assign) BOOL adjustsFontSizeToFitHeight;

@end

UILabel+FitToHeight.m

#import "UILabel+FitToHeight.h"

#import 

@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 vous le feriez avec n'importe quelle autre catégorie...

#import "UILabel+FitToHeight.h"

et utilisez comme suit...

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

Il convient de noter que cela fonctionne toujours avec [titleLabel setAdjustsFontSizeToFitWidth:YES]; donc l'utilisation des deux en conjonction est tout à fait possible.

1voto

ely87 Points 91

Variation SWIFT :

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

extension UILabel {

//Trouve et définit une taille de police qui correspond à la hauteur du cadre. 
//Utilisez si la taille de la police est énorme et que vous devez la redimensionner.
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--
    }

    //Dans le cas où le texte est trop long, nous montrons quand même quelque chose... ;)
    if (currentfontSize == minFontsize){
        font = font.fontWithSize(currentfontSize)
    }
}

}

1voto

Savagewood Points 2131

En s'appuyant sur la réponse épique de Joel Fisher mais écrite comme une extension Swift 4 :

extension String {

    /// Tente de retourner la police spécifiée par le nom de la taille de point appropriée
    /// pour que cette chaîne s'adapte à l'intérieur d'une taille de conteneur particulière et
    /// contrainte à une taille de point minimale et maximale.
    /// - parameter name: de la police.
    /// - parameter containerSize: dans laquelle cette chaîne devrait s'adapter.
    /// - parameter lowerBound: taille de point minimale autorisée de cette police.
    /// - parameter upperBound: taille de point maximale autorisée de cette police.
    /// - returns: la police spécifiée par le nom de la taille de point appropriée
    /// pour que cette chaîne s'adapte à l'intérieur d'une taille de conteneur particulière et
    /// contrainte à une taille de point minimale et maximale; `nil` si aucune
    /// police de ce type n'existe.
    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))
    }

    /// Renvoie la police système de la taille de point appropriée pour que cette chaîne
    /// s'adapte à l'intérieur d'une taille de conteneur particulière et contrainte à une taille
    /// de point minimale et maximale.
    /// - parameter containerSize: dans laquelle cette chaîne devrait s'adapter.
    /// - parameter lowerBound: taille de point minimale autorisée de cette police.
    /// - parameter upperBound: taille de point maximale autorisée de cette police.
    /// - returns: la police système de la taille de point appropriée pour que cette chaîne
    /// s'adapte à l'intérieur d'une taille de conteneur particulière et contrainte à une taille
    /// de point minimale et maximale.
    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 = "Chaîne de test".font(named: "Courier New",
                              toFit: CGSize(width: 150.0, height: 30.0),
                              noSmallerThan: 12.0,
                              noLargerThan: 20.0)
let sysfont = "Chaîne de test".systemFont(toFit: CGSize(width: 150.0, height: 30.0),
                                       noSmallerThan: 12.0,
                                       noLargerThan: 20.0)

0voto

ObjectiveTC Points 129

Pour les UILabels qui redimensionnent de manière proportionnelle pour les appareils plus grands / plus petits :

La solution la plus efficace pour moi a été de définir la taille de police à un ratio de la hauteur du label +/- un facteur d'ajustement. En supposant l'utilisation de contraintes de mise en page automatique, positionnez son axe vertical y au centre du bas de la super vue, multiplié par un ratio. De même dans IB, contrainte la largeur du label à une proportion de la largeur de l'écran.

Facultativement, vous pouvez verrouiller le rapport hauteur/largeur du label avec une contrainte d'aspect, cependant cela peut provoquer un clipping si vous ne calculez pas correctement la taille de police. La seule raison de verrouiller le rapport d'aspect est si les positions des autres contrôles/vues sont relatives à ce label. Cependant, je recommande vivement de placer ces contrôles/vues par rapport à la hauteur/largeur de la super vue afin qu'ils ne dépendent pas de ce label.

Je comprends que ce n'est pas exactement une solution encapsulée, mais cela m'a causé le moins de soucis de manière constante. La seule autre solution qui s'en rapprochait faisait appel à des boucles while, cependant dans mon cas je ne pouvais pas supporter les retards imposés à chaque appel de système de mise en page/rafraîchissement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X