web-dev-qa-db-fra.com

Modification dynamique de la taille de la police de UILabel

J'ai actuellement une 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 la UILabel de sorte que la taille de la police change de sorte que le texte tienne toujours dans les limites que j'ai définies?

179
CodeGuy

Une seule ligne:

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

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

Plusieurs lignes:

Pour numberOfLines > 1, il existe une méthode permettant de déterminer la taille du texte final par le biais de méthodes sizeWithFont: ... UIKit de NSString , par exemple:

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

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

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

iOS6

Une seule ligne:

À partir de iOS6, minimumFontSize est obsolète. La ligne

factLabel.minimumFontSize = 8.;

peut être changé en:

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

iOS7

Plusieurs lignes:

À partir de iOS7, sizeWithFont 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);
343
Martin Babacaev

minimumFontSize est 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.

67
Amit Singh

Selon la réponse de @Eyal Ben Dov, vous souhaiterez peut-être 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

- Usage

#import "UILabel+DynamicFontSize.h"

[myUILabel adjustFontSizeToFillItsContents];

À votre santé

24

Une seule ligne - Il y a deux façons de changer.

1- Pragmatiquement (Swift 3)

Ajoutez simplement le code suivant

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

2 - Utiliser 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)

enter image description here

22
Devendra Singh

Nous sommes en 2015. Je devais trouver un article de blog qui expliquerait comment utiliser la dernière version d'iOS et de XCode avec Swift pour qu'il fonctionne avec plusieurs lignes.

  1. réglez "Autoshrink" sur "Taille minimale de la police".
  2. définir la police à la plus grande taille de police souhaitée (j'ai choisi 20)
  3. Modifiez les "sauts de ligne" de "Retour automatique à la ligne" en "Tronquer la queue".

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

20
zavtra

Version rapide:

textLabel.adjustsFontSizeToFitWidth = true
textLabel.minimumScaleFactor = 0.5
12
Esqarrouth

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.

SAGE:<label> est votre UILabel prédéfini qui nécessite un redimensionnement de la police.

<label>.fitFontForSize()

Par défaut, cette fonction effectue une recherche dans les tailles de police comprises entre 5 et 300 points et définit la police pour adapter son texte "parfaitement" à l'intérieur des limites (avec une précision de moins de 1,0 point). Vous pouvez définir les paramètres pour que, par exemple, il recherche entre 1pt et la taille de police actuelle du libellé avec précision à l'intérieur de .1pts de la manière suivante :

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

Copiez/Collez 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
    }

}

NOTE: Chacun des appels layoutIfNeeded() peut être supprimé à votre propre discrétion.

7
Avi Frankl

Son un peu peu 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
Eyal Ben Dov

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

[textViewA1 sizeToFit];
1
codercat

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

@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
videolist

Cette solution fonctionne pour multiligne:

Après avoir suivi plusieurs articles et exigé une fonction qui redimensionnerait automatiquement le texte et ajusterait le nombre de lignes pour correspondre au mieux à la taille de l'étiquette donnée, j'ai écrit une fonction moi-même. (c.-à-d. une ficelle courte irait bien sur une ligne et utiliserait une grande partie du cadre de l'étiquette, alors qu'une chaîne forte et longue se scinderait automatiquement en 2 ou 3 lignes et ajusterait la taille en conséquence)

N'hésitez pas à le réutiliser et à modifier au besoin. Assurez-vous de l'appeler une fois que viewDidLayoutSubviews est terminé afin que le cadre d'étiquette initial ait é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
aaroncatlin

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
Phil