Domanda Allinea verticalmente il testo in cima a un UILabel


Ho un UILabel con spazio per due righe di testo. A volte, quando il testo è troppo corto, questo testo viene visualizzato nel centro verticale dell'etichetta.

Come allineare verticalmente il testo per essere sempre in cima al UILabel?

image representing a UILabel with vertically-centered text


1984
2018-06-28 08:54


origine


risposte:


Non c'è modo di impostare l'allineamento verticale su a UILabel, ma puoi ottenere lo stesso effetto cambiando la cornice dell'etichetta. Ho reso le mie etichette arancione in modo da poter vedere chiaramente cosa sta succedendo.

Ecco il modo semplice e veloce per farlo:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


Se hai un'etichetta con testo più lungo che creerà più di una riga, imposta numberOfLines a 0 (zero qui significa un numero illimitato di linee).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with sizeToFit


Versione più lunga

Farò la mia etichetta in codice in modo che tu possa vedere cosa sta succedendo. Puoi anche configurare la maggior parte di questo in Interface Builder. La mia configurazione è un'applicazione basata su immagini con un'immagine di sfondo che ho realizzato in Photoshop per mostrare i margini (20 punti). L'etichetta è di un attraente colore arancione in modo da poter vedere cosa sta succedendo con le dimensioni.

- (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];
}

Alcune limitazioni di utilizzo sizeToFit entra in gioco con testo allineato al centro o alla destra. Ecco cosa succede:

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

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

enter image description here

L'etichetta è ancora dimensionata con un angolo fisso in alto a sinistra. È possibile salvare la larghezza dell'etichetta originale in una variabile e impostarla dopo sizeToFit, o dargli una larghezza fissa per contrastare questi problemi:

    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


Nota che sizeToFit rispetterà la larghezza minima della tua etichetta iniziale. Se inizi con un'etichetta larga 100 e chiama sizeToFit su di esso, ti restituirà un'etichetta (possibilmente molto alta) con 100 (o un po 'meno) di larghezza. Potrebbe essere necessario impostare l'etichetta sulla larghezza minima desiderata prima di ridimensionarla.

Correct label alignment by resizing the frame width

Alcune altre cose da notare:

Se lineBreakMode è rispettato dipende da come è impostato. NSLineBreakByTruncatingTail (il valore predefinito) viene ignorato dopo sizeToFit, come lo sono le altre due modalità di troncamento (testa e centro). NSLineBreakByClipping è anche ignorato. NSLineBreakByCharWrapping funziona come al solito. La larghezza della cornice è ancora ridotta per adattarsi alla lettera più a destra.


Mark Amery ha fornito una correzione per NIB e Storyboard utilizzando Auto Layout nei commenti:

Se la tua etichetta è inclusa in un pennino o uno storyboard come sottoview del view di un ViewController che utilizza l'autolayout, quindi inserisce il tuo sizeToFit chiamare in viewDidLoad non funzionerà, perché le dimensioni dell'autolayout e posizionano le sottoview dopo viewDidLoad viene chiamato e annullerà immediatamente gli effetti del tuo sizeToFit chiamata. Tuttavia, chiamando sizeToFit dall'interno viewDidLayoutSubviews  volere lavoro.


La mia risposta originale (per i posteri / riferimento):

Questo usa il NSString metodo sizeWithFont:constrainedToSize:lineBreakMode: per calcolare l'altezza del fotogramma necessaria per adattare una stringa, quindi imposta l'origine e la larghezza.

Ridimensiona la cornice per l'etichetta usando il testo che vuoi inserire. In questo modo puoi sistemare qualsiasi numero di linee.

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. Imposta il nuovo testo:

    myLabel.text = @"Some Text"
    
  2. Impostare il maximum number di linee a 0 (automatico):

    myLabel.numberOfLines = 0
    
  3. Imposta la cornice dell'etichetta sulla dimensione massima:

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. Chiamata sizeToFit per ridurre le dimensioni della cornice in modo che i contenuti si adattino perfettamente:

    [myLabel sizeToFit]
    

La cornice delle etichette ora è alta e larga abbastanza per adattarsi al tuo testo. In alto a sinistra dovrebbe essere invariato. Ho provato questo solo con il testo allineato in alto a sinistra. Per altri allineamenti, potrebbe essere necessario modificare successivamente il frame.

Inoltre, la mia etichetta ha attivato il word wrapping.


315
2017-08-27 16:24



Riferendosi alla soluzione di estensione:

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

dovrebbe essere sostituito da

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

Spazio aggiuntivo è necessario in ogni nuova riga aggiunta, perché iPhone UILabels"i ritorni a capo trascinati sembrano essere ignorati :(

Allo stesso modo, alignBottom dovrebbe essere aggiornato anche con a @" \n@%" al posto di "\n@%" (per l'inizializzazione del ciclo deve essere sostituito da "for (int i = 0 ...").

La seguente estensione funziona per me:

// -- 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

Quindi chiama [yourLabel alignTop]; o [yourLabel alignBottom]; dopo ogni assegnazione di testo di YourLabel.


151
2017-09-09 13:01



Nel caso in cui sia di aiuto a qualcuno, ho avuto lo stesso problema ma sono riuscito a risolvere il problema semplicemente passando dall'uso UILabel usare UITextView. Apprezzo che questo non è per tutti, perché la funzionalità è un po 'diversa.

Se si passa a utilizzare UITextView, puoi disattivare tutte le proprietà di Scroll View e Interazione utente abilitata ... Questo lo obbligherà ad agire più come un'etichetta.

enter image description here


126
2017-10-05 12:46



Niente muss, niente storie

@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

No muss, no Objective-c, nessun clamore ma 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



Come la risposta di cui sopra, ma non era giusto, o facile da battere sul codice, così l'ho ripulito un po '. Aggiungi questa estensione al proprio file .h e .m o semplicemente incolla sopra l'implementazione che intendi utilizzarla:

#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

E poi da usare, metti il ​​tuo testo nell'etichetta e poi chiama il metodo appropriato per allinearlo:

[myLabel alignTop];

o

[myLabel alignBottom];

76
2018-03-04 02:44



Un modo ancora più rapido (e più sporco) per farlo è impostare la modalità di interruzione di riga di UILabel su "Clip" e aggiungere una quantità fissa di newline.

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

Questa soluzione non funzionerà per tutti - in particolare, se vuoi ancora mostrare "..." alla fine della stringa se supera il numero di linee che stai visualizzando, dovrai utilizzare uno dei seguenti i bit più lunghi del codice - ma per molti casi questo ti porterà ciò di cui hai bisogno.


66
2018-04-18 21:08



Invece di UILabel Puoi usare UITextField che ha l'opzione di allineamento verticale:

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

56
2018-02-10 10:36



Ho lottato con questo per molto tempo e volevo condividere la mia soluzione.

Questo ti darà un UILabel questo ridurrà il testo automaticamente a 0,5 scale e centrerà verticalmente il testo. Queste opzioni sono disponibili anche in Storyboard / IB.

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

47
2017-10-16 16:38



Crea una nuova classe

LabelTopAlign

.h file

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

.m file

#import "KwLabelTopAlign.h"


@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect {
    int lineHeight = [@"IglL" sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, 9999.0f)].height;
    if(rect.size.height >= lineHeight) {
        int textHeight = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, rect.size.height)].height;
        int yMax = textHeight;
        if (self.numberOfLines > 0) {
            yMax = MIN(lineHeight*self.numberOfLines, yMax);    
        }

        [super drawTextInRect:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, yMax)];
    }
}

@end

modificare

Ecco un'implementazione più semplice che fa lo stesso:

#import "KwLabelTopAlign.h"

@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect
{
    CGFloat height = [self.text sizeWithFont:self.font
                            constrainedToSize:rect.size
                                lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    rect.size.height = MIN(rect.size.height, height);
    [super drawTextInRect:rect];
}

@end

42
2017-08-04 08:07



enter image description here

In Interface Builder

  • Impostato UILabel alla dimensione del più grande testo possibile
  • Impostato Lines a "0" nell'Inspector degli attributi

Nel tuo codice

  • Imposta il testo dell'etichetta
  • Chiamata sizeToFit sulla tua etichetta

Snippet di codice:

self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];

38
2018-01-03 04:40