web-dev-qa-db-fra.com

Aligner verticalement UILabel

J'essaie d'aligner verticalement le texte dans la vue UILabel de mon application. Le problème est que je veux que le texte soit aligné verticalement vers le haut et que la taille de l'étiquette soit de 280 x 150. Je ne peux réaliser qu'une de ces deux choses. Si je supprime la ligne

[myLabel sizeToFit];

alors l'alignement du texte est correct mais la taille est foirée. Mais si j'ajoute la ligne ci-dessus, l'alignement est altéré mais la taille est correcte. Comment puis-je résoudre ce problème.

J'ai ajouté le code ci-dessous -

CGRect labelFrame = CGRectMake(22, 50, 280, 150);
UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
[myLabel setText:finalRecipe];
[myLabel setBackgroundColor: [UIColor lightGrayColor]];
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
[self.view addSubview:myLabel];
10
Ashish Agarwal

Je suis l'auteur de FXLabel et, même si je ne connais pas Manish, je crois qu'il essayait de l'aider (s'il me faisait de la publicité, je ne le lui ai certainement pas demandé et je ne le paye pas - désolé Manish!).

L'une des fonctionnalités de FXLabel est qu'il respecte la propriété UIContentMode de l'étiquette, telle que définie dans le générateur Interface. Cela signifie que vous pouvez définir label.contentMode = UIViewContentModeTop; pour aligner le texte en haut de la vue des étiquettes (ce qui ne fonctionne pas pour un UILabel standard). L'exemple pertinent est ici:

https://github.com/nicklockwood/FXLabel/tree/master/Examples/Text%20Alignment

FXLabel est une sous-classe de UILabel, donc je pense que c'est une très bonne solution pour la question posée. Cependant, si l’affiche préfère résoudre le problème sans utiliser de bibliothèque tierce (ce qui est compréhensible), voici le code pour le faire:

CGRect labelFrame = CGRectMake(22, 50, 280, 150);
UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
[myLabel setText:finalRecipe];
[myLabel setBackgroundColor: [UIColor lightGrayColor]];
[myLabel setNumberOfLines:0];

CGFloat fontSize = 0.0f;
labelFrame.size = [myLabel.text sizeWithFont:myLabel.font
                                minFontSize:myLabel.minimumFontSize
                             actualFontSize:&fontSize
                                   forWidth:labelFrame.width
                            lineBreakMode:myLabel.lineBreakMode];

myLabel.frame = labelFrame;
[self.view addSubview:myLabel];

Note: (Ceci n'est pas testé, donc excuses s'il y a des fautes de frappe)

12
Nick Lockwood

ne pas utiliser UILabel pour cela. Utilisez UIButton avec UserInteractionEnabled = NO; et qui dispose d'options pour aligner le texte verticalement ou horizontalement.

Voici:

Rapide:

btnDetail.titleLabel?.numberOfLines = 5
btnDetail.titleLabel?.lineBreakMode = .byCharWrapping
btnDetail.contentVerticalAlignment = .top
btnDetail.contentHorizontalAlignment = .left
btnDetail.isUserInteractionEnabled = false
btnDetail.autoresizesSubviews = true
btnDetail.autoresizingMask = .flexibleWidth

Obj-C

[btnDetail.titleLabel setNumberOfLines:5];
[btnDetail.titleLabel setLineBreakMode:NSLineBreakByCharWrapping];
[btnDetail setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];
[btnDetail setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[btnDetail setUserInteractionEnabled:NO];
btnDetail.autoresizesSubviews = YES;
btnDetail.autoresizingMask = UIViewAutoresizingFlexibleWidth;
17
Vaibhav Saran

Vous devrez sous-classer UILabel. Essaye ça:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];
    rect.size.height = MIN(rect.size.height, sizeThatFits.height);

    [super drawTextInRect:rect];
}

Comme vous l'avez découvert, UILabel centre verticalement le texte dans ses limites. Ici, nous demandons à -sizeThatFits la taille du bloc de texte et l’utilisons pour contraindre le rectangle de dessin transmis à UILabel, de sorte que le texte soit tracé à partir du haut des limites de l’étiquette.

Vous pouvez même supporter la propriété contentMode ignorée (soupir) comme ceci:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];

    if (self.contentMode == UIViewContentModeTop) {
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }
    else if (self.contentMode == UIViewContentModeBottom) {
        rect.Origin.y = MAX(0, rect.size.height - sizeThatFits.height);
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }

    [super drawTextInRect:rect];
}

Il existe de nombreuses autres solutions et discussions ici: Aligner verticalement le texte en haut dans un UILabel

12
jrc

Dans Swift, la solution du JRC de sous-classer UILabel, de remplacer drawTextInRect et de se conformer à UIViewContentMode ressemblerait à ceci:

class AlignableUILabel: UILabel {

    override func drawText(in rect: CGRect) {

        var newRect = CGRect(x: rect.Origin.x,y: rect.Origin.y,width: rect.width, height: rect.height)
        let fittingSize = sizeThatFits(rect.size)

        if contentMode == UIViewContentMode.top {
            newRect.size.height = min(newRect.size.height, fittingSize.height)
        } else if contentMode == UIViewContentMode.bottom {
            newRect.Origin.y = max(0, newRect.size.height - fittingSize.height)
        }

        super.drawText(in: newRect)
    }

}

La mise en œuvre est simplement une question de:

yourLabel.contentMode = UIViewContentMode.top

Pour moi, cela a fonctionné comme un charme.

9
Roshambo

Il existe un moyen de ne pas sous-classer, en utilisant un bouton ou en roulant le vôtre.

définissez le nombre de lignes sur 0, puis appelez sizeToFit.

[label setNumberOfLines:0];
[label sizeToFit];

Plus de détails ici comme je pense que quelqu'un d'autre est lié à: Aligner verticalement le texte en haut dans un UILabel

1
Cocoadelica

Vous pouvez le faire avec une contrainte sur le constructeur d'interface.

  1. Mettez le nombre de lignes que vous voulez
  2. Créez une contrainte avec une hauteur suffisante pour 3 lignes et dans la section relation, indiquez "Inférieur ou égal à".

J'espère que cela vous aidera!

1
Joffrey Outtier

Beau bidouillage ... mes deux sous pour Swift 4.2/5:

self.optTextMessage.numberOfLines =  0
self.optTitle.lineBreakMode  = .byWordWrapping

et ajoutez\n .. comme suggéré ..

0
ingconti

Je l'ai fait ce que vous voulez en implémentant une catégorie:

.h

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

.m

@implementation UILabel (VerticalAlign)

#pragma mark
#pragma mark - Align Methods

- (void)alignTop
{
    [self setFrame:[self newLabelFrame:UIControlContentVerticalAlignmentTop]];
}

- (void)alignBottom
{
    [self setFrame:[self newLabelFrame:UIControlContentVerticalAlignmentBottom]];
}

#pragma mark
#pragma mark - Helper Methods

- (CGRect)newLabelFrame:(UIControlContentVerticalAlignment)alignment
{
    CGRect labelRect = self.frame;

    NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading;

    CGRect textRect = [self.text boundingRectWithSize:CGSizeMake(227.f, CGFLOAT_MAX)
                                              options:options
                                           attributes:@{NSFontAttributeName:self.font}
                                              context:nil];

    CGFloat textOffset = labelRect.size.height - textRect.size.height;

    UIEdgeInsets contentInsets;
    if (alignment == UIControlContentVerticalAlignmentTop)
    {
        if (textOffset < (labelRect.size.height/2.f))
        {
            contentInsets = UIEdgeInsetsMake(-textOffset, 0.f, 0.f, 0.f);
        }
        else
        {
            contentInsets = UIEdgeInsetsMake(0.f, 0.f, textOffset, 0.f);
        }
    }
    else
    {
        if (textOffset < (labelRect.size.height/2.f))
        {
            contentInsets = UIEdgeInsetsMake(0.f, 0.f, -textOffset, 0.f);
        }
        else
        {
            contentInsets = UIEdgeInsetsMake(textOffset, 0.f, 0.f, 0.f);
        }
    }

    return UIEdgeInsetsInsetRect(labelRect, contentInsets);
}

@end

N'oubliez pas que vous devez définir "NumberOfLines" sur 0. Cet exemple fonctionne avec les options multilignes!

Après avoir implémenté la catégorie ci-dessus, vous pouvez simplement faire:

[myLabel setText:finalRecipe];
[myLabel alignTop];

À votre santé!

0
Tom Calmon