60 votes

Rétrécissement automatique d'un UILabel avec plusieurs lignes

Est-il possible d'utiliser la propriété autoshrink en conjonction avec plusieurs lignes d'un document de type UILabel ? par exemple, la grande taille du texte possible sur 2 lignes disponibles.

0 votes

J'ai fait un pas de plus et répondu à votre question pour qu'il prenne en charge les étiquettes multilignes et cliquables et qu'il soit compatible avec Swift 5. Vous trouverez ma réponse ci-dessous. J'espère que cela vous aidera !

49voto

DaGaMs Points 934

J'ai modifié quelque peu le code de la réponse acceptée pour en faire une catégorie sur UILabel :

Fichier d'en-tête :

#import <UIKit/UIKit.h>
@interface UILabel (MultiLineAutoSize)
    - (void)adjustFontSizeToFit;
@end

Et le fichier de mise en œuvre :

@implementation UILabel (MultiLineAutoSize)

- (void)adjustFontSizeToFit
{
    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumFontSize; maxSize -= 1.f)
    {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
        CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
        if(labelSize.height <= size.height)
        {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }
    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout];
}

@end

0 votes

Super, je viens de tomber sur cette question moi-même et cela la résout en un rien de temps :-) Juste deux remarques : (1) les deux premières lignes en intérieur if sont redondants, puisqu'ils seront exécutés juste en dessous de la clause for cycle. (2) si le texte d'UILabel doit également être aligné verticalement en haut (au cas où il utilise moins de lignes que ce qui peut être affiché dans l'étiquette), il suffit de définir la hauteur de l'étiquette sur labelSize.height. Notez que sizeToFit ne peut pas être utilisé à cette fin, car il casse le texte précédemment formaté et le taille à la taille de la police d'origine.

5 votes

C'est parfait, mais minimumFontSize est déprécié dans iOS6 - comment pourrait-on changer cela pour fonctionner avec minimumScaleFactor à la place ?

0 votes

Juste ce dont j'avais besoin. Merci. +1

39voto

The dude Points 3567

Ces personnes ont trouvé une solution :

http://www.11pixel.com/blog/28/resize-multi-line-text-to-fit-uilabel-on-iphone/

Leur solution est la suivante :

int maxDesiredFontSize = 28;
int minFontSize = 10;
CGFloat labelWidth = 260.0f;
CGFloat labelRequiredHeight = 180.0f;
//Create a string with the text we want to display.
self.ourText = @"This is your variable-length string. Assign it any way you want!";

/* This is where we define the ideal font that the Label wants to use.
   Use the font you want to use and the largest font size you want to use. */
UIFont *font = [UIFont fontWithName:@"Marker Felt" size:maxDesiredFontSize];

int i;
/* Time to calculate the needed font size.
   This for loop starts at the largest font size, and decreases by two point sizes (i=i-2)
   Until it either hits a size that will fit or hits the minimum size we want to allow (i > 10) */
for(i = maxDesiredFontSize; i > minFontSize; i=i-2)
{
    // Set the new font size.
    font = [font fontWithSize:i];
    // You can log the size you're trying: NSLog(@"Trying size: %u", i);

    /* This step is important: We make a constraint box 
       using only the fixed WIDTH of the UILabel. The height will
       be checked later. */ 
    CGSize constraintSize = CGSizeMake(labelWidth, MAXFLOAT);

    // This step checks how tall the label would be with the desired font.
    CGSize labelSize = [self.ourText sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

    /* Here is where you use the height requirement!
       Set the value in the if statement to the height of your UILabel
       If the label fits into your required height, it will break the loop
       and use that font size. */
    if(labelSize.height <= labelRequiredHeight)
        break;
}
// You can see what size the function is using by outputting: NSLog(@"Best size is: %u", i);

// Set the UILabel's font to the newly adjusted font.
msg.font = font;

// Put the text into the UILabel outlet variable.
msg.text = self.ourText;

Pour que cela fonctionne, un IBOutlet doit être attribué à l'UILabel dans le constructeur de l'interface.

"IBOutlet UILabel *msg ;"

Tout le mérite revient aux gens de 11pixel.

24voto

stevenpaulr Points 131

Voici la solution de catégorie mise à jour pour iOS 7, basée sur les mises à jour d'itecedor pour iOS 6.

Fichier d'en-tête :

#import <UIKit/UIKit.h>
@interface UILabel (MultiLineAutoSize)
    - (void)adjustFontSizeToFit;
@end

Et le fichier de mise en œuvre :

@implementation UILabel (MultiLineAutoSize)

- (void)adjustFontSizeToFit {
    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f)
    {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);

        CGRect textRect = [self.text boundingRectWithSize:constraintSize
                                             options:NSStringDrawingUsesLineFragmentOrigin
                                          attributes:@{NSFontAttributeName:font}
                                             context:nil];

        CGSize labelSize = textRect.size;

        if(labelSize.height <= size.height)
        {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }
    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout]; }

@end

2 votes

Ne devez-vous pas appliquer le minimumScaleFactor à la taille initiale du point ? (par exemple, si le facteur est de 0,5, vous pourriez obtenir des polices très petites ici).

1 votes

Cela fonctionne comme un charme, mais n'oubliez pas de définir la valeur YES pour l'étiquette UILabel dans le paramètre adjustsFontSizeToFitWidth.

6voto

john.k.doe Points 5481

J'ai bien aimé la réponse de DaGaMs, mais en utilisant des étiquettes comme dans les UITableViewCells qui peuvent être renvoyées par dequeueReusableCell :, la taille de la police normale continuerait à diminuer même si la taille de la police d'origine est toujours souhaitée pour certaines cellules de tableView qui ont moins de texte et qui peuvent profiter de la taille de la police d'origine de l'étiquette.

Ainsi, en partant de la catégorie de DaGaMs comme point de départ, j'ai créé une classe distincte plutôt qu'une catégorie distincte, et je m'assure que mes UILabels dans mon storyboard utilisent cette nouvelle classe :

#import "MultiLineAutoShrinkLabel.h"

@interface MultiLineAutoShrinkLabel ()
@property (readonly, nonatomic) UIFont* originalFont;
@end

@implementation MultiLineAutoShrinkLabel

@synthesize originalFont = _originalFont;

- (UIFont*)originalFont { return _originalFont ? _originalFont : (_originalFont = self.font); }

- (void)quoteAutoshrinkUnquote
{
    UIFont* font = self.originalFont;
    CGSize frameSize = self.frame.size;

    CGFloat testFontSize = _originalFont.pointSize;
    for (; testFontSize >= self.minimumFontSize; testFontSize -= 0.5)
    {
        CGSize constraintSize = CGSizeMake(frameSize.width, MAXFLOAT);
        CGSize testFrameSize = [self.text sizeWithFont:(font = [font fontWithSize:testFontSize])
                                     constrainedToSize:constraintSize
                                         lineBreakMode:self.lineBreakMode];
        // the ratio of testFontSize to original font-size sort of accounts for number of lines
        if (testFrameSize.height <= frameSize.height * (testFontSize/_originalFont.pointSize))
            break;
    }

    self.font = font;
    [self setNeedsLayout];
}

@end

1 votes

+1 pour traiter les UITableViewCells. Mais où se trouve le code de votre interface MultilineAutoShrinkLabel.h ?

0 votes

@Rhubarb, c'est juste trivial : sous-classe de UILabel avec une seule fonction, - (void)quoteAutoshrinkUnquote; et en fait, j'ai évolué vers quelque chose de similaire mais un peu plus compliqué qui gère l'accessoryView sur le côté droit et le fait qu'il peut être de 2 tailles différentes, permettant plus ou moins de surface d'écran par cellule.

0 votes

J'ai utilisé cette réponse pour répondre à ma propre question et j'ai également mis à jour le code pour supprimer les méthodes obsolètes. stackoverflow.com/a/30898604/758083

6voto

Abras Points 193

La réponse de itedcedor présente un problème que pwightman a souligné. De plus, il n'est pas nécessaire de couper les espaces. Voici la version modifiée :

- (void)adjustFontSizeToFit {
    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f) {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
        CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];

        if(labelSize.height <= size.height) {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }

    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout];
}

0 votes

Le problème que je rencontre avec cette méthode est que le texte semble être aligné à gauche, quoi que l'on fasse. Mise à jour : il semble que le fait de décocher la case "Resserrer l'espacement des lettres" résout ce problème.

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