Frage Richten Sie den Text in einem UILabel vertikal nach oben aus


Ich habe ein UILabel mit Platz für zwei Zeilen Text. Manchmal, wenn der Text zu kurz ist, wird dieser Text in der vertikalen Mitte des Etiketts angezeigt.

Wie richte ich den Text vertikal aus, um immer an der Spitze der UILabel?

image representing a UILabel with vertically-centered text


1984
2018-06-28 08:54


Ursprung


Antworten:


Es gibt keine Möglichkeit, die vertikale Ausrichtung auf a festzulegen UILabel, aber Sie können den gleichen Effekt erzielen, indem Sie den Rahmen des Etiketts ändern. Ich habe meine Etiketten orange gemacht, damit du klar sehen kannst, was passiert.

Hier ist der schnelle und einfache Weg, dies zu tun:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


Wenn Sie eine Beschriftung mit längerem Text haben, die mehr als eine Zeile enthält, legen Sie fest numberOfLines zu 0 (Null bedeutet hier eine unbegrenzte Anzahl von Zeilen).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with sizeToFit


Längere Version

Ich mache mein Label in Code, damit Sie sehen können, was vor sich geht. Sie können das meiste auch im Interface Builder einrichten. Meine Einrichtung ist eine View-basierte App mit einem Hintergrundbild, das ich in Photoshop erstellt habe, um die Ränder anzuzeigen (20 Punkte). Das Etikett ist eine attraktive orange Farbe, so dass Sie sehen können, was mit den Abmessungen passiert.

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

Einige Einschränkungen der Verwendung sizeToFit mit zentriertem oder rechtsbündigem Text ins Spiel kommen. Folgendes passiert:

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

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

enter image description here

Das Etikett hat immer noch eine feste obere linke Ecke. Sie können die Breite des ursprünglichen Etiketts in einer Variablen speichern und danach festlegen sizeToFitoder geben Sie ihm eine feste Breite, um diesen Problemen zu begegnen:

    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


Beachten Sie, dass sizeToFit respektiert die Mindestbreite Ihres Anfangslabels. Wenn du mit einem Label 100 weit anfängst und anrufst sizeToFit darauf gibt es Ihnen ein (möglicherweise sehr hohes) Etikett mit 100 (oder etwas weniger) Breite zurück. Möglicherweise möchten Sie Ihr Label vor der Größenanpassung auf die gewünschte Mindestbreite einstellen.

Correct label alignment by resizing the frame width

Einige andere Dinge zu beachten:

Ob lineBreakMode wird respektiert, hängt davon ab, wie es eingestellt ist. NSLineBreakByTruncatingTail (der Standard) wird danach ignoriert sizeToFit, wie auch die anderen beiden Abschneidemodi (Kopf und Mitte). NSLineBreakByClipping wird auch ignoriert. NSLineBreakByCharWrapping funktioniert wie immer. Die Rahmenbreite ist immer noch schmaler, um an den am weitesten rechts stehenden Buchstaben zu passen.


Mark Amery gab eine Reparatur für NIBs und Storyboards mit Auto Layout in den Kommentaren:

Wenn Ihr Label in einer Nib oder Storyboard als Unteransicht der view eines ViewControllers, der automatisches Layout verwendet, sizeToFit einwählen viewDidLoad funktioniert nicht, da die Größe automatisch angepasst wird und die Unteransichten danach positioniert werden viewDidLoad wird gerufen und wird sofort die Auswirkungen Ihrer rückgängig machen sizeToFit Anruf. Rufen jedoch an sizeToFit von innen viewDidLayoutSubviews  werden Arbeit.


Meine ursprüngliche Antwort (für Nachwelt / Referenz):

Dies verwendet die NSString Methode sizeWithFont:constrainedToSize:lineBreakMode: um die Rahmenhöhe zu berechnen, die zum Anpassen einer Zeichenfolge benötigt wird, und legt dann den Ursprung und die Breite fest.

Ändern Sie die Größe des Rahmens für das Etikett mit dem Text, den Sie einfügen möchten. Auf diese Weise können Sie beliebig viele Zeilen unterbringen.

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. Setze den neuen Text:

    myLabel.text = @"Some Text"
    
  2. Stellen Sie das ein maximum number von Linien auf 0 (automatisch):

    myLabel.numberOfLines = 0
    
  3. Setzen Sie den Rahmen des Labels auf die maximale Größe:

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. Anruf sizeToFit um die Rahmengröße zu reduzieren, damit der Inhalt genau passt:

    [myLabel sizeToFit]
    

Der Etikettenrahmen ist jetzt gerade hoch und breit genug, um zu Ihrem Text zu passen. Die obere linke sollte unverändert sein. Ich habe das nur mit linksbündigem Text getestet. Bei anderen Ausrichtungen müssen Sie den Rahmen möglicherweise später ändern.

Auf meinem Label ist auch die Umbruchfunktion aktiviert.


315
2017-08-27 16:24



Verweis auf die Erweiterungslösung:

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

sollte ersetzt werden durch

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

Zusätzlicher Platz wird in jedem hinzugefügten Newline benötigt, weil iPhone UILabels'Trailing Carriage Returns scheint ignoriert zu werden :(

Analog sollte alignBottom auch mit a aktualisiert werden @" \n@%" anstelle von "\n@%" (für Zyklusinitialisierung muss durch "für (int i = 0 ..." auch ersetzt werden).

Die folgende Erweiterung funktioniert für mich:

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

Dann ruf an [yourLabel alignTop]; oder [yourLabel alignBottom]; nach jeder Zuweisung von yourLabel-Text.


151
2017-09-09 13:01



Nur für den Fall, dass es für irgendjemanden hilfreich ist, hatte ich das gleiche Problem, konnte aber das Problem einfach lösen, indem ich von der Verwendung umstellte UILabel zu benutzen UITextView. Ich schätze, dass dies nicht für jedermann ist, da die Funktionalität ein bisschen anders ist.

Wenn Sie zur Verwendung wechseln UITextViewSie können alle Eigenschaften der Bildlaufansicht sowie die Benutzerinteraktion aktiviert deaktivieren ... Dadurch wird es gezwungen, sich mehr wie eine Beschriftung zu verhalten.

enter image description here


126
2017-10-05 12:46



Kein Muss, kein Aufhebens

@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

Nein Muss, kein Objective-c, keine Aufregung aber 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



Wie die Antwort oben, aber es war nicht ganz richtig, oder einfach, Code zu schlagen, also habe ich es ein wenig aufgeräumt. Fügen Sie diese Erweiterung entweder zu ihrer eigenen .h- und .m-Datei hinzu oder fügen Sie sie direkt über der Implementierung ein, die Sie verwenden möchten:

#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

Fügen Sie dann Ihren Text in das Etikett ein und rufen Sie dann die entsprechende Methode zum Ausrichten auf:

[myLabel alignTop];

oder

[myLabel alignBottom];

76
2018-03-04 02:44



Ein noch schnellerer (und dreckigerer) Weg, dies zu erreichen, besteht darin, den Zeilenumbruchmodus von UILabel auf "Clip" zu setzen und eine bestimmte Anzahl von Zeilenumbrüchen hinzuzufügen.

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

Diese Lösung wird nicht für alle funktionieren. Wenn Sie beispielsweise "..." am Ende der Zeichenfolge anzeigen möchten, wenn die Anzahl der angezeigten Zeilen überschritten wird, müssen Sie eine der folgenden Optionen verwenden die längeren Bits des Codes - aber für viele Fälle erhalten Sie, was Sie brauchen.


66
2018-04-18 21:08



Anstatt von UILabel du darfst verwenden UITextField mit vertikaler Ausrichtung:

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

56
2018-02-10 10:36



Ich habe lange mit diesem Problem gekämpft und wollte meine Lösung teilen.

Dies wird Ihnen einen geben UILabel Dadurch wird der Text automatisch auf 0,5 Skalen verkleinert und der Text vertikal zentriert. Diese Optionen sind auch im Storyboard / IB verfügbar.

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

47
2017-10-16 16:38