Question Aligner verticalement le texte au sommet d'un UILabel


j'ai un UILabel avec un espace pour deux lignes de texte. Parfois, lorsque le texte est trop court, ce texte est affiché dans le centre vertical de l'étiquette.

Comment aligner verticalement le texte pour toujours être en haut de UILabel?

image representing a UILabel with vertically-centered text


1984
2018-06-28 08:54


origine


Réponses:


Il n'y a aucun moyen de définir l'alignement vertical sur un UILabel, mais vous pouvez obtenir le même effet en changeant le cadre de l'étiquette. J'ai rendu mes étiquettes orange afin que vous puissiez voir clairement ce qui se passe.

Voici la manière rapide et facile de faire ceci:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


Si vous avez une étiquette avec du texte plus long qui fera plus d'une ligne, définissez numberOfLines à 0 (zéro signifie ici un nombre illimité de lignes).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with sizeToFit


Version plus longue

Je vais faire mon label dans le code pour que vous puissiez voir ce qui se passe. Vous pouvez également configurer la plupart de ces fonctionnalités dans Interface Builder. Ma configuration est une application View Based avec une image de fond que j'ai faite dans Photoshop pour montrer les marges (20 points). L'étiquette est une couleur orange attrayante afin que vous puissiez voir ce qui se passe avec les dimensions.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 20 point top and left margin. Sized to leave 20 pt at right.
    CGRect labelFrame = CGRectMake(20, 20, 280, 150);
    UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
    [myLabel setBackgroundColor:[UIColor orangeColor]];

    NSString *labelText = @"I am the very model of a modern Major-General, I've information vegetable, animal, and mineral";
    [myLabel setText:labelText];

    // Tell the label to use an unlimited number of lines
    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    [self.view addSubview:myLabel];
}

Quelques limites d'utilisation sizeToFit entrer en jeu avec le texte aligné au centre ou à droite. Voici ce qui se passe:

    // myLabel.textAlignment = NSTextAlignmentRight;
    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

enter image description here

L'étiquette est toujours dimensionnée avec un coin supérieur gauche fixe. Vous pouvez enregistrer la largeur de l'étiquette d'origine dans une variable et la définir après sizeToFitou lui donner une largeur fixe pour contrer ces problèmes:

    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    CGRect myFrame = myLabel.frame;
    // Resize the frame's width to 280 (320 - margins)
    // width could also be myOriginalLabelFrame.size.width
    myFrame = CGRectMake(myFrame.origin.x, myFrame.origin.y, 280, myFrame.size.height);
    myLabel.frame = myFrame;

label alignment


Notez que sizeToFit respectera la largeur minimale de votre étiquette initiale. Si vous commencez avec une étiquette 100 large et appelez sizeToFit dessus, il vous rendra une étiquette (peut-être très grande) avec une largeur de 100 (ou un peu moins). Vous souhaiterez peut-être définir votre étiquette sur la largeur minimale souhaitée avant le redimensionnement.

Correct label alignment by resizing the frame width

Quelques autres choses à noter:

Qu'il s'agisse lineBreakMode est respecté dépend de la façon dont il est défini. NSLineBreakByTruncatingTail (la valeur par défaut) est ignorée après sizeToFit, comme le sont les deux autres modes de troncature (tête et milieu). NSLineBreakByClipping est également ignoré. NSLineBreakByCharWrapping fonctionne comme d'habitude. La largeur du cadre est toujours réduite pour correspondre à la lettre la plus à droite.


Mark Amery a donné une solution pour les NIB et Storyboards en utilisant Auto Layout dans les commentaires:

Si votre étiquette est incluse dans une plume ou un storyboard en tant que sous-vue du view d'un ViewController qui utilise autolayout, puis en mettant votre sizeToFit Téléphoner à viewDidLoad ne fonctionnera pas, car les tailles autolayout et positionne les sous-vues après viewDidLoad est appelé et va immédiatement annuler les effets de votre sizeToFit appel. Cependant, appeler sizeToFit de l'Intérieur viewDidLayoutSubviews  volonté travail.


Ma réponse originale (pour la postérité / référence):

Cela utilise le NSString méthode sizeWithFont:constrainedToSize:lineBreakMode: pour calculer la hauteur du cadre nécessaire pour s'adapter à une chaîne, puis définit l'origine et la largeur.

Redimensionnez le cadre de l'étiquette en utilisant le texte que vous souhaitez insérer. De cette façon, vous pouvez accueillir n'importe quel nombre de lignes.

CGSize maximumSize = CGSizeMake(300, 9999);
NSString *dateString = @"The date today is January 1st, 1999";
UIFont *dateFont = [UIFont fontWithName:@"Helvetica" size:14];
CGSize dateStringSize = [dateString sizeWithFont:dateFont 
        constrainedToSize:maximumSize 
        lineBreakMode:self.dateLabel.lineBreakMode];

CGRect dateFrame = CGRectMake(10, 10, 300, dateStringSize.height);

self.dateLabel.frame = dateFrame;

2561
2018-06-28 10:36



  1. Définissez le nouveau texte:

    myLabel.text = @"Some Text"
    
  2. Met le maximum number de lignes à 0 (automatique):

    myLabel.numberOfLines = 0
    
  3. Définir le cadre de l'étiquette à la taille maximale:

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. Appel sizeToFit pour réduire la taille de l'image afin que le contenu ne

    [myLabel sizeToFit]
    

Le cadre des étiquettes est maintenant juste assez haut et large pour s'adapter à votre texte. Le coin supérieur gauche devrait être inchangé. J'ai testé cela seulement avec le texte aligné en haut à gauche. Pour les autres alignements, vous devrez peut-être modifier le cadre par la suite.

De plus, mon libellé est activé pour l'étiquette.


315
2017-08-27 16:24



En référence à la solution d'extension:

for(int i=1; i< newLinesToPad; i++) 
    self.text = [self.text stringByAppendingString:@"\n"];

devrait être remplacé par

for(int i=0; i<newLinesToPad; i++)
    self.text = [self.text stringByAppendingString:@"\n "];

Un espace supplémentaire est nécessaire dans chaque nouvelle ligne ajoutée, car l'iPhone UILabels'retours de chariot à la traîne semble être ignoré :(

De même, alignBottom devrait être mis à jour avec un @" \n@%" au lieu de "\n@%" (pour initialiser le cycle, il faut remplacer "for (int i = 0 ..." aussi).

L'extension suivante fonctionne pour moi:

// -- file: UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end

// -- file: UILabel+VerticalAlign.m
@implementation UILabel (VerticalAlign)
- (void)alignTop {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [self.text stringByAppendingString:@"\n "];
}

- (void)alignBottom {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
}
@end

Puis appelez [yourLabel alignTop]; ou [yourLabel alignBottom]; après chaque affectation de texte yourLabel.


151
2017-09-09 13:01



Juste au cas où cela serait utile à tout le monde, j'ai eu le même problème mais j'étais capable de résoudre le problème simplement en passant de l'utilisation UILabel à l'aide UITextView. J'apprécie que ce n'est pas pour tout le monde parce que la fonctionnalité est un peu différente.

Si vous passez à l'utilisation UITextView, vous pouvez désactiver toutes les propriétés de la vue de défilement ainsi que l'interaction utilisateur activée ... Cela l'obligera à agir plus comme une étiquette.

enter image description here


126
2017-10-05 12:46



Pas de muss, pas de problème

@interface MFTopAlignedLabel : UILabel

@end


@implementation MFTopAlignedLabel

- (void)drawTextInRect:(CGRect) rect
{
    NSAttributedString *attributedText = [[NSAttributedString alloc]     initWithString:self.text attributes:@{NSFontAttributeName:self.font}];
    rect.size.height = [attributedText boundingRectWithSize:rect.size
                                            options:NSStringDrawingUsesLineFragmentOrigin
                                            context:nil].size.height;
    if (self.numberOfLines != 0) {
        rect.size.height = MIN(rect.size.height, self.numberOfLines * self.font.lineHeight);
    }
    [super drawTextInRect:rect];
}

@end

Pas de muss, pas d'objectif-c, pas d'histoire mais Swift 3:

class VerticalTopAlignLabel: UILabel {

    override func drawText(in rect:CGRect) {
        guard let labelText = text else {  return super.drawText(in: rect) }

        let attributedText = NSAttributedString(string: labelText, attributes: [NSFontAttributeName: font])
        var newRect = rect
        newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height

        if numberOfLines != 0 {
            newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
        }

        super.drawText(in: newRect)
    }

}

80
2018-05-21 07:47



Comme la réponse ci-dessus, mais ce n'était pas tout à fait correct, ou facile à copier dans le code, donc je l'ai nettoyé un peu. Ajoutez cette extension à son propre fichier .h et .m ou collez juste au-dessus de l'implémentation que vous avez l'intention de l'utiliser:

#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end


@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i<= newLinesToPad; i++)
    {
        self.text = [self.text stringByAppendingString:@" \n"];
    }
}

- (void)alignBottom
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i< newLinesToPad; i++)
    {
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
    }
}
@end

Ensuite, pour utiliser, placez votre texte dans l'étiquette, puis appelez la méthode appropriée pour l'aligner:

[myLabel alignTop];

ou

[myLabel alignBottom];

76
2018-03-04 02:44



Un moyen encore plus rapide (et plus sale) d'y parvenir est de régler le mode de saut de ligne de UILabel sur "Clip" et d'ajouter un nombre fixe de retours à la ligne.

myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];

Cette solution ne fonctionnera pas pour tout le monde - en particulier, si vous voulez toujours afficher "..." à la fin de votre chaîne si elle dépasse le nombre de lignes que vous affichez, vous devrez utiliser l'un des les bits les plus longs du code - mais pour beaucoup de cas cela vous donnera ce dont vous avez besoin.


66
2018-04-18 21:08



Au lieu de UILabel vous pouvez utiliser UITextField qui a l'option d'alignement vertical:

textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction

56
2018-02-10 10:36



J'ai lutté avec celui-ci depuis longtemps et je voulais partager ma solution.

Cela vous donnera un UILabel cela va automatiquement réduire le texte à 0.5 échelles et centrer verticalement le texte. Ces options sont également disponibles dans Storyboard / IB.

[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];

47
2017-10-16 16:38