2344 Stimmen

Text innerhalb eines UILabels vertikal nach oben ausrichten

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

Wie kann ich den Text vertikal so ausrichten, dass er sich immer am oberen Rand der UILabel ?

image representing a UILabel with vertically-centered text

0 Stimmen

2776voto

nevan king Punkte 110579

Es gibt keine Möglichkeit, die vertikale Ausrichtung bei einer UILabel aber Sie können den gleichen Effekt erzielen, indem Sie den Rahmen des Etiketts ändern. Ich habe meine Etiketten orange gefärbt, damit Sie deutlich sehen können, was passiert.

So geht's schnell und einfach:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


Wenn Sie ein Etikett mit längerem Text haben, der mehr als eine Zeile ausmachen soll, setzen Sie numberOfLines a 0 (Null bedeutet hier eine unbegrenzte Anzahl von Zeilen).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with sizeToFit


Längere Version

Ich werde mein Etikett im Code erstellen, damit Sie sehen können, was vor sich geht. Sie können das meiste davon auch im Interface Builder einrichten. Bei meinem Setup handelt es sich um eine ansichtsbasierte App mit einem Hintergrundbild, das ich in Photoshop erstellt habe, um die Ränder anzuzeigen (20 Punkte). Das Etikett hat eine attraktive orange Farbe, damit 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 bei der Verwendung sizeToFit kommen bei zentriertem oder rechtsbündigem Text ins Spiel. Das passiert folgendermaßen:

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

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

enter image description here

Das Etikett hat nach wie vor die gleiche Größe und eine feste Ecke oben links. Sie können die ursprüngliche Breite des Etiketts in einer Variablen speichern und sie nach sizeToFit oder mit einer festen Breite versehen, um diese Probleme zu vermeiden:

    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 wird die Mindestbreite des ursprünglichen Etiketts respektieren. Wenn Sie mit einem 100 breiten Etikett beginnen und sizeToFit darauf, erhalten Sie ein (möglicherweise sehr hohes) Etikett mit einer Breite von 100 (oder etwas weniger) zurück. Vielleicht möchten Sie Ihr Etikett vor der Größenänderung auf die gewünschte Mindestbreite einstellen.

Correct label alignment by resizing the frame width

Einige andere Dinge sind zu beachten:

Ob lineBreakMode beachtet wird, hängt davon ab, wie es eingestellt ist. NSLineBreakByTruncatingTail (der Standardwert) wird ignoriert, nachdem sizeToFit sowie die beiden anderen Abschneidungsarten (Kopf und Mitte). NSLineBreakByClipping wird ebenfalls ignoriert. NSLineBreakByCharWrapping funktioniert wie gewohnt. Die Rahmenbreite wird nach wie vor auf den ganz rechten Buchstaben eingeengt.


Mark Amery hat in den Kommentaren einen Fix für NIBs und Storyboards mit Auto-Layout angegeben:

Wenn Ihr Label in einer Feder oder einem Storyboard als Unteransicht der view eines ViewControllers, der Autolayout verwendet, dann setzen Sie Ihre sizeToFit hereinrufen viewDidLoad wird nicht funktionieren, da das automatische Layout die Größe und Position der Unteransichten nach viewDidLoad aufgerufen und macht sofort die Auswirkungen Ihrer sizeToFit anrufen. Allerdings ist der Anruf sizeToFit von innen viewDidLayoutSubviews se Arbeit.


Meine ursprüngliche Antwort (für die Nachwelt/zum Nachschlagen):

Dabei wird die NSString Methode sizeWithFont:constrainedToSize:lineBreakMode: um die Höhe des Rahmens zu berechnen, die für eine Zeichenkette benötigt wird, und setzt dann den Ursprung und die Breite.

Ändern Sie die Größe des Rahmens für die Beschriftung anhand des Textes, den Sie einfügen möchten. Auf diese Weise können Sie eine beliebige Anzahl von 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;

12 Stimmen

Sie müssen Autolayout entfernen

4 Stimmen

Es gibt eine einfache Möglichkeit, das Problem zu lösen: stackoverflow.com/a/26632490/636559

0 Stimmen

Wenn Sie Auto-Layout und Storyboard verwenden, hilft das Hinzufügen einer Einschränkung mit der Option "Remove at build time".

344voto

Jakob Egger Punkte 11631
  1. Legen Sie den neuen Text fest:

    myLabel.text = @"Some Text"
  2. Stellen Sie die maximum number der Zeilen auf 0 (automatisch):

    myLabel.numberOfLines = 0
  3. Stellen Sie den Rahmen des Etiketts auf die maximale Größe ein:

    myLabel.frame = CGRectMake(20,20,200,800)
  4. Rufen Sie an. sizeToFit um den Rahmen zu verkleinern, damit der Inhalt gerade noch hineinpasst:

    [myLabel sizeToFit]

Der Etikettenrahmen ist jetzt gerade hoch und breit genug, um Ihren Text aufzunehmen. Die obere linke Seite sollte unverändert bleiben. Ich habe dies nur mit dem oben links ausgerichteten Text getestet. Bei anderen Ausrichtungen müssen Sie den Rahmen möglicherweise nachträglich ändern.

Außerdem ist bei meinem Etikett der Wortumbruch aktiviert.

0 Stimmen

Das hat bei mir gut funktioniert. Ich habe die Abmessungen meines UILabels eingestellt und numberOfLines in IB auf 0 geändert und dann nach dem Einstellen des Textes [myLabel sizeToFit] aufgerufen.

0 Stimmen

Funktioniert bei mir perfekt, nachdem ich die Anzahl der Zeilen in Attr. Inspektor

0 Stimmen

Funktioniert nicht, wenn die Anzahl der Zeilen mehr als 1 beträgt

166voto

jowie Punkte 7957

Nur für den Fall, dass es jemandem hilft: Ich hatte das gleiche Problem, konnte es aber lösen, indem ich von der Verwendung von UILabel zu verwenden UITextView . Ich bin mir bewusst, dass dies nicht für jeden geeignet ist, da die Funktionalität ein wenig anders ist.

Wenn Sie auf die Verwendung von UITextView können Sie alle Eigenschaften der Bildlaufansicht sowie die Option Benutzerinteraktion aktiviert... deaktivieren. Dies wird es zwingen, mehr wie ein Etikett zu handeln.

enter image description here

1 Stimmen

Ich bin nicht sicher, wie sich dies auf die Leistung auswirkt, wenn viele UILabels in Textansichten umgewandelt werden.

2 Stimmen

Alle anderen Lösungen in diesem Thread haben bei mir unter iOS 7 nicht funktioniert (aus welchem Grund auch immer). Aber einfach mit einem UITextView brachte mir auf Anhieb das gewünschte Ergebnis.

1 Stimmen

Es ist ein Workaround, es braucht noch einige Anpassungen, damit es authentisch aussieht, aber in der Tat ist dies die einfachste Lösung ohne Code, die ich gesehen habe, Daumen hoch.

164voto

Bezogen 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 "];

Für jeden hinzugefügten Zeilenumbruch wird ein zusätzliches Leerzeichen benötigt, da das iPhone UILabels Nachfolgende Zeilenumbrüche werden anscheinend ignoriert :(

In ähnlicher Weise sollte auch alignBottom mit einer @" \n@%" anstelle von "\n@%" (für die Zyklusinitialisierung muss ebenfalls durch "for(int i=0..." ersetzt werden).

Die folgende Erweiterung funktioniert bei mir:

// -- 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 rufen Sie [yourLabel alignTop]; o [yourLabel alignBottom]; nach jeder Zuweisung von yourLabel-Text.

0 Stimmen

@D.S. Ich habe bemerkt, dass Sie Folgendes hinzufügen VerticalAlign zwischen Klammern nach @implementation UILabel . Da ich neu in Objective-C bin, bin ich noch nie auf diese Syntax gestoßen. Wie nennt man das?

0 Stimmen

Erstaunlich, ich wusste nichts von Kategorien, das gibt mir noch mehr Wertschätzung für die Sprache Objective-c. Das Erlernen weiterer Sprachen ist so wichtig, um ein guter Programmierer zu werden.

0 Stimmen

Gab ein upvote. aber iirc dies wird nicht funktionieren, wenn Sie nicht wissen, die Anzahl der Zeilen, die ein Nachteil ist

147voto

jasongregori Punkte 11001

Kein Durcheinander, 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

Kein Durcheinander, kein Objective-c, kein Aufhebens, sondern 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)
    }

}

Swift 4.2

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: [NSAttributedString.Key.font: 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)
    }

}

0 Stimmen

Die schnelle Version hat bei mir ohne jegliche Nebenwirkungen funktioniert! Tolle Arbeit!

10 Stimmen

Wahrscheinlich die beste Antwort hier, funktioniert in allen Szenarien. sizeToFit funktioniert nicht, wenn Label in UITableviewCell ist. Gute Arbeit.

1 Stimmen

Lieber Apple, es sollte nicht so schwer sein, Text automatisch nach links oben zu bringen. Das heißt, große Antwort hier @jasongregori . Ich habe das Hugging-Konzept und die obere Antwort ausprobiert, aber beides hat bei einem CollectionViewCell-Label nicht funktioniert. Eine eigene Klasse für UILabel ist die Lösung.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X