Modification dynamique de la taille de la police de UILabel

J'ai actuellement un UILabel:

factLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 280, 100)];
factLabel.text = @"some text some text some text some text";
factLabel.backgroundColor = [UIColor clearColor];
factLabel.lineBreakMode = UILineBreakModeWordWrap;
factLabel.numberOfLines = 10;
[self.view addSubview:factLabel];

Tout au long de la vie de mon application iOS, factLabel obtient un tas de valeurs différentes. Certains avec plusieurs phrases, d'autres avec seulement 5 ou 6 mots.

Comment puis-je configurer le UILabel de sorte que la taille de la police change pour que le texte corresponde toujours aux limites que j'ai définies?

168
demandé sur Andreas 2011-02-01 19:53:13

12 réponses

Ligne unique:

factLabel.numberOfLines = 1;
factLabel.minimumFontSize = 8;
factLabel.adjustsFontSizeToFitWidth = YES;

Le code ci-dessus ajustera la taille de police de votre texte à (par exemple) 8 en essayant d'adapter votre texte dans l'étiquette. numberOfLines = 1 est obligatoire.

Plusieurs lignes:

Pour numberOfLines > 1 Il existe une méthode pour déterminer la taille du texte final à travers les méthodes UIKit addition de {[23] NSString, par exemple:

CGSize lLabelSize = [yourText sizeWithFont: factLabel.font forWidth:factLabel.frame.size.width lineBreakMode:factLabel.lineBreakMode];

Après, vous pouvez simplement redimensionner votre étiquette en utilisant résultant lLabelSize, par exemple (en supposant que vous ne changera que la hauteur de l'étiquette):

factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, factLabel.frame.size.width, lLabelSize.height);

IOS6

Ligne unique:

Depuis iOS6, minimumFontSize est obsolète. La ligne

factLabel.minimumFontSize = 8.;

Peut être changé en:

factLabel.minimumScaleFactor = 8./factLabel.font.pointSize;

IOS7

Plusieurs lignes:

À partir d'iOS7, {[11] } devient obsolète. Le cas multiligne est réduit à:

factLabel.numberOfLines = 0;
factLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(factLabel.frame.size.width, CGFLOAT_MAX);
CGSize expectSize = [factLabel sizeThatFits:maximumLabelSize];
factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, expectSize.width, expectSize.height);
327
répondu Martin Babacaev 2015-09-20 17:13:39

minimumFontSize a été obsolète avec iOS 6. Vous pouvez utiliser minimumScaleFactor.

yourLabel.adjustsFontSizeToFitWidth=YES;
yourLabel.minimumScaleFactor=0.5;

Cela prendra soin de votre taille de police en fonction de la largeur de l'étiquette et du texte.

60
répondu Amit Singh 2016-05-19 18:59:33

Basé sur la réponse de @Eyal Ben Dov, vous pouvez créer une catégorie pour la rendre flexible à utiliser dans une autre application de la vôtre.

Obs.: J'ai mis à jour son code pour le rendre compatible avec iOS 7

-fichier d'en-Tête

#import <UIKit/UIKit.h>

@interface UILabel (DynamicFontSize)

-(void) adjustFontSizeToFillItsContents;

@end

-Fichier D'implémentation

#import "UILabel+DynamicFontSize.h"

@implementation UILabel (DynamicFontSize)

#define CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE 35
#define CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE 3

-(void) adjustFontSizeToFillItsContents
{
    NSString* text = self.text;

    for (int i = CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE; i>CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE; i--) {

        UIFont *font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
        NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];

        CGRect rectSize = [attributedText boundingRectWithSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil];

        if (rectSize.size.height <= self.frame.size.height) {
            self.font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
            break;
        }
    }

}

@end

-l'Utilisation de

#import "UILabel+DynamicFontSize.h"

[myUILabel adjustFontSizeToFillItsContents];

Santé

22
répondu Paulo Miguel Almeida 2014-01-27 13:30:35

C'est 2015. Je devais aller trouver un article de blog qui expliquerait comment le faire pour la dernière version d'iOS et XCode avec Swift afin que cela fonctionne avec plusieurs lignes.

  1. définissez " Autoshrink "sur" Taille de police minimale."
  2. Définir la police à la plus grande taille de police souhaitable (j'ai choisi 20)
  3. Changer " sauts de ligne "de" Wrap Word "à" tronquer la queue."

Source: http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/

20
répondu zavtra 2015-06-26 18:26:44

Seule ligne- Il y a deux façons, vous pouvez simplement changer.

1 - De Façon Pragmatique (Swift 3)

Ajoutez simplement le code suivant

    yourLabel.numberOfLines = 1;
    yourLabel.minimumScaleFactor = 0.7;
    yourLabel.adjustsFontSizeToFitWidth = true;

2-Utilisation de l'inspecteur D'attributs UILabel

i- Select your label- Set number of lines 1.
ii- Autoshrink-  Select Minimum Font Scale from drop down
iii- Set Minimum Font Scale value as you wish , I have set 0.7 as in below image. (default is 0.5)

entrez la description de l'image ici

15
répondu Devendra Singh 2017-08-04 18:34:15

Version Swift:

textLabel.adjustsFontSizeToFitWidth = true
textLabel.minimumScaleFactor = 0.5
10
répondu Esqarrouth 2015-06-02 21:21:18

Voici une extension Swift pour UILabel. Il exécute un algorithme de recherche binaire pour redimensionner la police en fonction de la largeur et de la hauteur des limites de l'étiquette. Testé pour fonctionner avec iOS 9 et autolayout.

Utilisation: <label> est votre UILabel prédéfini qui doit être redimensionné

<label>.fitFontForSize()

Par défaut, cette fonction recherche dans la plage de tailles de police 5pt et 300pt et définit la police pour adapter son texte "parfaitement" dans les limites (précis dans 1.0 pt). Vous pouvez définir les paramètres de sorte qu'il, par exemple, Recherche entre 1pt et la taille de police actuelle de l'étiquette avec précision dans 0.1 pts de la manière suivante:

<label>.fitFontForSize(1.0, maxFontSize: <label>.font.pointSize, accuracy:0.1)

Copier/Coller le code suivant dans votre fichier

extension UILabel {

    func fitFontForSize(var minFontSize : CGFloat = 5.0, var maxFontSize : CGFloat = 300.0, accuracy : CGFloat = 1.0) {
        assert(maxFontSize > minFontSize)
        layoutIfNeeded() // Can be removed at your own discretion
        let constrainedSize = bounds.size
        while maxFontSize - minFontSize > accuracy {
            let midFontSize : CGFloat = ((minFontSize + maxFontSize) / 2)
            font = font.fontWithSize(midFontSize)
            sizeToFit()
            let checkSize : CGSize = bounds.size
            if  checkSize.height < constrainedSize.height && checkSize.width < constrainedSize.width {
                minFontSize = midFontSize
            } else {
                maxFontSize = midFontSize
            }
        }
        font = font.fontWithSize(minFontSize)
        sizeToFit()
        layoutIfNeeded() // Can be removed at your own discretion
    }

}

REMARQUE: chacun des appels layoutIfNeeded() peut être supprimé à votre propre discrétion

7
répondu Avi Frankl 2015-12-31 02:47:50

C'est un peu pas sophistiqué mais cela devrait fonctionner, par exemple, disons que vous voulez plafonner votre uilabel à 120x120, avec une taille de police maximale de 28:

magicLabel.numberOfLines = 0;
magicLabel.lineBreakMode = NSLineBreakByWordWrapping;
...
magicLabel.text = text;
    for (int i = 28; i>3; i--) {
        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:(CGFloat)i] constrainedToSize:CGSizeMake(120.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
        if (size.height < 120) {
            magicLabel.font = [UIFont systemFontOfSize:(CGFloat)i];
            break;
        }
    }
4
répondu Eyal Ben Dov 2013-06-11 22:51:51

Envoyez simplement le message sizeToFit à L'UITextView. Il ajustera sa propre hauteur pour s'adapter à son texte. Il ne changera pas sa propre largeur ou origine.

[textViewA1 sizeToFit];
1
répondu codercat 2014-03-05 11:10:52

Version Swift 2.0:

private func adapteSizeLabel(label: UILabel, sizeMax: CGFloat) {
     label.numberOfLines = 0
     label.lineBreakMode = NSLineBreakMode.ByWordWrapping
     let maximumLabelSize = CGSizeMake(label.frame.size.width, sizeMax);
     let expectSize = label.sizeThatFits(maximumLabelSize)
     label.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y, expectSize.width, expectSize.height)
}
0
répondu Phil 2016-03-16 09:27:15

Cette solution fonctionne pour multiligne:

Après avoir suivi plusieurs articles, et nécessitant une fonction qui mettrait automatiquement à l'échelle le texte et ajusterait le nombre de lignes pour mieux s'adapter à la taille de l'étiquette donnée, j'ai écrit une fonction moi-même. (IE. une chaîne courte s'adapterait bien sur une ligne et utiliserait une grande quantité du cadre de l'étiquette, alors qu'une longue forte se diviserait automatiquement sur 2 ou 3 lignes et ajusterait la taille en conséquence)

N'hésitez pas à le réutiliser et à le modifier au besoin. Faire bien sûr, vous l'appelez après viewDidLayoutSubviews a terminé de sorte que le cadre d'étiquette initial a été défini.

+ (void)setFontForLabel:(UILabel *)label withMaximumFontSize:(float)maxFontSize andMaximumLines:(int)maxLines {
    int numLines = 1;
    float fontSize = maxFontSize;
    CGSize textSize; // The size of the text
    CGSize frameSize; // The size of the frame of the label
    CGSize unrestrictedFrameSize; // The size the text would be if it were not restricted by the label height
    CGRect originalLabelFrame = label.frame;

    frameSize = label.frame.size;
    textSize = [label.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize: fontSize]}];

    // Work out the number of lines that will need to fit the text in snug
    while (((textSize.width / numLines) / (textSize.height * numLines) > frameSize.width / frameSize.height) && (numLines < maxLines)) {
        numLines++;
    }

    label.numberOfLines = numLines;

    // Get the current text size
    label.font = [UIFont systemFontOfSize:fontSize];
    textSize = [label.text boundingRectWithSize:CGSizeMake(frameSize.width, CGFLOAT_MAX)
                                        options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                     attributes:@{NSFontAttributeName : label.font}
                                        context:nil].size;

    // Adjust the frame size so that it can fit text on more lines
    // so that we do not end up with truncated text
    label.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y, label.frame.size.width, label.frame.size.width);

    // Get the size of the text as it would fit into the extended label size
    unrestrictedFrameSize = [label textRectForBounds:CGRectMake(0, 0, label.bounds.size.width, CGFLOAT_MAX) limitedToNumberOfLines:numLines].size;

    // Keep reducing the font size until it fits
    while (textSize.width > unrestrictedFrameSize.width || textSize.height > frameSize.height) {
        fontSize--;
        label.font = [UIFont systemFontOfSize:fontSize];
        textSize = [label.text boundingRectWithSize:CGSizeMake(frameSize.width, CGFLOAT_MAX)
                                            options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                         attributes:@{NSFontAttributeName : label.font}
                                            context:nil].size;
        unrestrictedFrameSize = [label textRectForBounds:CGRectMake(0, 0, label.bounds.size.width, CGFLOAT_MAX) limitedToNumberOfLines:numLines].size;
    }

    // Set the label frame size back to original
    label.frame = originalLabelFrame;
}
0
répondu aaroncatlin 2016-04-10 13:07:03

Voici le code de remplissage d'une sous-classe UILabel qui implémente le changement de taille de police animée:

@interface SNTextLayer : CATextLayer

@end

@implementation SNTextLayer

- (void)drawInContext:(CGContextRef)ctx {
    // We override this to make text appear at the same vertical positon as in UILabel
    // (otherwise it's shifted tdown)
    CGFloat height = self.bounds.size.height;
    float fontSize = self.fontSize;
    // May need to adjust this somewhat if it's not aligned perfectly in your implementation
    float yDiff = (height-fontSize)/2 - fontSize/10;

    CGContextSaveGState(ctx);
    CGContextTranslateCTM(ctx, 0.0, yDiff);
    [super drawInContext:ctx];
     CGContextRestoreGState(ctx);
}

@end

@interface SNAnimatableLabel ()

@property CATextLayer* textLayer;

@end

@interface SNAnimatableLabel : UILabel

- (void)animateFontToSize:(CGFloat)fontSize withDuration:(double)duration;

@end



@implementation SNAnimatableLabel


- (void)awakeFromNib {
    [super awakeFromNib];
    _textLayer = [SNTextLayer new];
    _textLayer.backgroundColor = self.backgroundColor.CGColor;
    _textLayer.foregroundColor = self.textColor.CGColor;
    _textLayer.font = CGFontCreateWithFontName((CFStringRef)self.font.fontName);
    _textLayer.frame = self.bounds;
    _textLayer.string = self.text;
    _textLayer.fontSize = self.font.pointSize;
    _textLayer.contentsScale = [UIScreen mainScreen].scale;
    [_textLayer setPosition: CGPointMake(CGRectGetMidX(_textLayer.frame), CGRectGetMidY(_textLayer.frame))];
    [_textLayer setAnchorPoint: CGPointMake(0.5, 0.5)];
    [_textLayer setAlignmentMode: kCAAlignmentCenter];
    self.textColor = self.backgroundColor;
    // Blend text with background, so that it doens't interfere with textlayer text
    [self.layer addSublayer:_textLayer];
    self.layer.masksToBounds = NO;
}

- (void)setText:(NSString *)text {
    _textLayer.string = text;
    super.text = text;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    // Need to enlarge the frame, otherwise the text may get clipped for bigger font sizes
    _textLayer.frame = CGRectInset(self.bounds, -5, -5);
}

- (void)animateFontToSize:(CGFloat)fontSize withDuration:(double)duration {
    [CATransaction begin];
    [CATransaction setAnimationDuration:duration];
    _textLayer.fontSize = fontSize;
    [CATransaction commit];
}
0
répondu videolist 2016-05-31 01:52:01