Richten Sie den Text innerhalb eines UILabels vertikal nach oben aus


2175

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

Wie richte ich den Text vertikal aus, damit er immer oben auf dem Text steht UILabel?

Bild, das ein UILabel mit vertikal zentriertem Text darstellt

Antworten:


2702

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

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

    [myLabel sizeToFit];

sizeToFit, um ein Etikett zusammenzudrücken


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

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Längerer Beschriftungstext mit sizeToFit


Längere Version

Ich werde mein Etikett im Code erstellen, damit Sie sehen können, was los ist. Das meiste davon können Sie auch im Interface Builder einrichten. Mein Setup ist eine ansichtsbasierte App mit einem Hintergrundbild, das ich in Photoshop erstellt habe, um Ränder (20 Punkte) anzuzeigen. Das Etikett hat eine attraktive orange Farbe, sodass Sie sehen können, was mit den Abmessungen los ist.

- (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 sizeToFittreten bei mittig oder rechts ausgerichtetem Text auf. Folgendes passiert:

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

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

Geben Sie hier die Bildbeschreibung ein

Das Etikett hat immer noch eine feste Größe mit einer festen oberen linken Ecke. Sie können die Breite des Originaletiketts in einer Variablen speichern und danach festlegen sizeToFitoder eine feste Breite festlegen , um diesen Problemen entgegenzuwirken:

    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;

Etikettenausrichtung


Beachten Sie, dass sizeToFitdie Mindestbreite Ihres ursprünglichen Etiketts eingehalten wird. Wenn Sie mit einem Etikett mit einer Breite von 100 beginnen und es aufrufen sizeToFit, erhalten Sie ein (möglicherweise sehr hohes) Etikett mit einer Breite von 100 (oder etwas weniger) zurück. Möglicherweise möchten Sie Ihre Beschriftung auf die gewünschte Mindestbreite einstellen, bevor Sie die Größe ändern.

Korrigieren Sie die Etikettenausrichtung, indem Sie die Rahmenbreite ändern

Einige andere Dinge zu beachten:

Ob dies lineBreakModerespektiert wird, hängt davon ab, wie es eingestellt ist. NSLineBreakByTruncatingTail(Standardeinstellung) wird nachher ignoriert sizeToFit, ebenso wie die beiden anderen Kürzungsmodi (Kopf und Mitte). NSLineBreakByClippingwird ebenfalls ignoriert. NSLineBreakByCharWrappingfunktioniert wie gewohnt. Die Rahmenbreite wird immer noch so verkleinert, dass sie zum Buchstaben ganz rechts passt.


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

Wenn Ihr Etikett in einer Schreibfeder oder einem Storyboard als Unteransicht vieweines ViewControllers enthalten ist, der Autolayout verwendet, funktioniert das Einfügen Ihres sizeToFitAnrufs viewDidLoadnicht, da Autolayout-Größen und -Positionen, nach denen die Unteransichten viewDidLoadaufgerufen werden, die Auswirkungen Ihrer sofort rückgängig machen sizeToFitAnruf. Allerdings fordert sizeToFitvon innen viewDidLayoutSubviews Willen Arbeit.


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

Dies verwendet die NSStringMethode sizeWithFont:constrainedToSize:lineBreakMode:, um die Rahmenhöhe zu berechnen, die zum Anpassen einer Zeichenfolge erforderlich ist, und legt dann den Ursprung und die Breite fest.

Ändern Sie die Größe des Rahmens für das Etikett anhand des Textes, den Sie einfügen möchten. Auf diese Weise können Sie eine beliebige Anzahl von Zeilen aufnehmen.

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;

10
Sie müssen Autolayout entfernen
hungbm06

4
Hier ist eine einfache Möglichkeit, das Problem zu lösen: stackoverflow.com/a/26632490/636559
AboulEinein

Wenn Sie das automatische Layout und das Storyboard verwenden, hilft das Hinzufügen einer Einschränkung mit aktivierter Option "Zur Erstellungszeit entfernen"
JK ABC

Wenn Sie dies benötigen, adjustsFontSizeToFitWidthverwenden Sie sizeToFit und setzen Sie den Rahmen des Etiketts auf 0, 0, theWidthYouWant, label.frame.size.height (dies ist die neue Größe, die durch sizeToFit bestimmt wird). DANN geltenadjustsFontSizeToFitWidth
Albert Renshaw

3
Diese Antwort ist unnötig kompliziert und verwendet ein "Wort um". Bitte beachten Sie den folgenden Vorschlag, einfach die Priorität für vertikale Inhalte zu ändern.
Benötigt

335
  1. Stellen Sie den neuen Text ein:

    myLabel.text = @"Some Text"
  2. Setzen Sie die maximum numberZeilen 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 sizeToFitan, um die Rahmengröße zu reduzieren, damit der Inhalt genau passt:

    [myLabel sizeToFit]

Der Beschriftungsrahmen ist jetzt gerade hoch und breit genug, um zu Ihrem Text zu passen. Oben links sollte unverändert bleiben. Ich habe dies nur mit dem oben links ausgerichteten Text getestet. Bei anderen Ausrichtungen müssen Sie möglicherweise den Rahmen anschließend ändern.

Außerdem ist auf meinem Etikett der Zeilenumbruch aktiviert.


Hey Ben, ich habe mir gerade meinen alten Code noch einmal angesehen und meine Antwort mit den richtigen Schritten aktualisiert.
Jakob Egger

Das hat bei mir gut funktioniert. Ich habe die Abmessungen meines UILabels festgelegt und numberOfLines in IB auf 0 geändert, nachdem ich den Text [myLabel sizeToFit] festgelegt habe.
Dan Ellis

funktioniert perfekt für mich, nachdem ich die Anzahl der Zeilen in Attr eingestellt habe. Inspektor
d2burke

Funktioniert nicht bei einer Anzahl von Zeilen über 1
Tom

Es funktioniert nicht, wenn Sie eine Beschriftung mit zwei Zeilen wünschen, aber der Text erfordert mehr Zeilen.
Jose Manuel Abarca Rodríguez

159

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

In jeder hinzugefügten neuen Zeile wird zusätzlicher Speicherplatz benötigt, da UILabelsdie nachlaufenden Wagenrückläufe des iPhone ignoriert zu werden scheinen :(

In ähnlicher Weise sollte auch alignBottom mit einem @" \n@%"anstelle von aktualisiert werden "\n@%"(für die Zyklusinitialisierung muss auch "for (int i = 0 ...") 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

Rufen Sie dann [yourLabel alignTop];oder [yourLabel alignBottom];nach jeder yourLabel-Textzuweisung auf.


@DS Ich habe festgestellt, dass Sie nach VerticalAlignzwischen Klammern hinzufügen @implementation UILabel. Als Neuling in Objective-C bin ich noch nie auf diese Syntax gestoßen. Wie heißt das?
Julian

Erstaunlich, wusste nichts über Kategorien, dies gibt mir noch mehr Wertschätzung für die Objective-c-Sprache. Mehr Sprachen zu lernen ist so wichtig, um ein guter Programmierer zu werden.
JeroenEijkhof

Hat eine Gegenstimme abgegeben. Aber dies funktioniert nicht, wenn Sie die Anzahl der Zeilen nicht kennen, was ein Nachteil ist
Tjirp

Ich muss 3 Textzeilen anzeigen und den Text nach oben ausrichten. Muss ich also die Anzahl der Zeilen auf 3 setzen? Wenn ich sie auf 3 setze, sehe ich "...", wenn der Text kleiner ist (das passt in eine Zeile). Wie vermeide
Satyam

1
Ich habe eine Bearbeitung dieser Kategorie veröffentlicht, die hoffentlich in Kürze genehmigt wird. Die Methoden sizeWithFont:constrainedToSize:lineBreakMode:und sizeWithFont: werden beide in iOS7 abgeschrieben. Außerdem funktioniert diese Kategorie nur bei Beschriftungen, wenn numberOfLines größer als 0 ist.
timgcarlson

146

Nur für den Fall, dass es jemandem hilft, hatte ich das gleiche Problem, konnte das Problem jedoch einfach durch Umschalten von "Verwenden" UILabelauf "Verwenden" lösen UITextView. Ich schätze, dass dies nicht jedermanns Sache ist, da die Funktionalität etwas anders ist.

Wenn Sie zu "Verwenden" wechseln UITextView, können Sie alle Eigenschaften der Bildlaufansicht sowie "Benutzerinteraktion aktiviert" deaktivieren. Dadurch wird die Verwendung eher wie eine Beschriftung erzwungen.

Geben Sie hier die Bildbeschreibung ein


1
Nicht sicher, wie sich dies auf die Leistung auswirkt, wenn viele UILabels in Textansichten konvertiert werden.
Ninjaneer

2
Alle anderen Lösungen in diesem Thread funktionierten in iOS 7 nicht für mich (aus welchem ​​Grund auch immer). Aber einfach mit a UITextViewhabe ich sofort das gewünschte Ergebnis erzielt.
Clifton Labrum

1
Es ist eine Problemumgehung, es müssen noch einige Anpassungen vorgenommen werden, damit es authentisch aussieht, aber in der Tat ist dies die einfachste Lösung ohne Code, die ich gesehen habe.
Itai Spector

1
Ich mag diese Lösung. Zugegeben, es kann Leistungsprobleme geben, und für ein einfaches Etikett in einer relativ einfachen Ansicht war dies perfekt für das, was ich brauchte (und ich kann keine Auswirkungen auf die Leistung feststellen)
JCutting8

1
Ein kleiner Nachteil dieser Methode besteht darin, dass dem Text eine zusätzliche Eigenauffüllung hinzugefügt wird. Eine schnelle Lösung besteht darin, eine negative Einschränkung einzuführen.
Sira Lam

122

Kein Muss, keine Aufregung

@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 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)
    }

}

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)
    }

}

Die schnelle Version hat bei mir ohne Nebenwirkungen funktioniert! Gute Arbeit!
l.vasilev

2
Die wahrscheinlich beste Antwort hier funktioniert in allen Szenarien. sizeToFit funktioniert nicht, wenn sich das Label in UITableviewCell befindet. Gute Arbeit.
Rajat Chauhan

79

Wie die Antwort oben, aber es war nicht ganz richtig oder einfach, in Code zu schlüpfen, also habe ich es ein bisschen 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 zur Verwendung Ihren Text in das Etikett ein und rufen Sie die entsprechende Methode zum Ausrichten auf:

[myLabel alignTop];

oder

[myLabel alignBottom];

sizeWithFont veraltet
tdios

68

Eine noch schnellere (und schmutzigere) Möglichkeit, dies zu erreichen, besteht darin, den Zeilenumbruchmodus des UILabel auf "Clip" zu setzen und eine feste Anzahl von Zeilenumbrüchen hinzuzufügen.

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

Diese Lösung funktioniert nicht für alle Benutzer. Insbesondere wenn Sie am Ende Ihrer Zeichenfolge immer noch "..." anzeigen möchten, wenn die Anzahl der angezeigten Zeilen überschritten wird, müssen Sie eine der folgenden Zeilen verwenden die längeren Codebits - aber in vielen Fällen erhalten Sie das, was Sie brauchen.


3
Das Einstellen des Zeilenumbruchmodus auf "Clip" scheint die automatische Größenänderung des Etiketts zu beeinträchtigen. Verwenden Sie UILineBreakModeWordWrapstattdessen.
Niels van der Rest

und besser Leerzeichen hinzufügen "\ n \ n"
djdance

68

Einfachster Ansatz mit Storyboard:

Einbetten Etikett in StackView und legen Sie die folgenden zwei Attribute von StackView im Attributinspektor fest:

1- AxisbisHorizontal ,

2- AlignmentbisTop

Geben Sie hier die Bildbeschreibung ein


1
Für bessere Ergebnisse können Sie dies tun: StackView> Ansicht> UILabel, denn wenn Sie nur ein UILabel in eine StackView einbetten, wird die Größe der StackView so angepasst, dass sie UILabel auf die Mindestgröße anpasst
Daniel Beltrami

Tolle Idee, UILabelin eine UIViewUnterklasse zu platzieren (einfach UIViewist normalerweise genug) und das Etikett nach unten wachsen zu lassen. Vielen Dank!
Viktor Kucera

1
Genial! Erwähnenswert ist auch, dass Sie Einschränkungen für UILabeldas StackView aufheben und seine Arbeit erledigen müssen. Vielen Dank!
Luiz Dias

Mit dem Menübefehl Editor-> Einbetten mit ausgewähltem Label werden die Beschriftungsbeschränkungen von Xcode für Sie gelöscht. Sie können dann einfach die Beschränkungen für die StackView festlegen. Dieser Ansatz kommt einem 'SwiftUI'-Layout-Ansatz am nächsten, wie ich ihn entdeckt habe.
Rocket Garden

Warum funktioniert das?
Novellizator

60

Anstelle von können UILabelSie verwenden, UITextFielddie vertikale Ausrichtungsoption hat:

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

7
Vorsichtsmaßnahme: UITextField erlaubt nur eine einzige Textzeile.
David James

2
Um @DavidJames Kommentar zu vervollständigen: UITextView wäre besser geeignet
CedricSoubrie

49

Ich habe lange mit diesem Problem zu kämpfen und wollte meine Lösung teilen.

Dadurch erhalten Sie einen UILabelText, der den Text automatisch auf 0,5 Skalen verkleinert und den Text vertikal zentriert. Diese Optionen sind auch in Storyboard / IB verfügbar.

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

Bei allen Antworten funktionierte es perfekt. Danke @David Greco. Wenn wir zusammen mit diesen Eigenschaften "adjustsFontSizeToFitWidth" auf "YES" setzen, passt der Text in den Rahmen, ohne den Rahmen des Etiketts zu ändern.
Ashok

43

Erstellen Sie eine neue Klasse

LabelTopAlign

.h Datei

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

.m Datei

#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

Bearbeiten

Hier ist eine einfachere Implementierung, die dasselbe tut:

#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

+1 für die echte Antwort. Im Gegensatz zu den sizeToFitLösungen das macht tatsächlich den UILabelPut jeden Text oben, auch wenn Sie dynamisch einen kürzeren Text mit einem längeren oder umgekehrt ersetzen.
SnakE

38

Geben Sie hier die Bildbeschreibung ein

Im Interface Builder

  • Auf UILabeldie Größe des größtmöglichen Textes einstellen
  • Im LinesAttributinspektor auf '0' setzen

In deinem Code

  • Legen Sie den Text des Etiketts fest
  • Rufen Sie sizeToFitIhr Etikett an

Code-Auszug:

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

hat super funktioniert, außer in meinem Fall musste ich Zeilen auf 2 setzen - ein UILabel in einer UITableViewCell haben und die Einstellung auf 0 hat es überlappt, aber die Einstellung auf 2 hat funktioniert (Zelle hat genug Platz für 2 Zeilen)
eselk

34

Für die adaptive Benutzeroberfläche (iOS8 oder höher) muss die vertikale Ausrichtung von UILabel in StoryBoard durch Ändern der Eigenschaften noOfLines= 0` und festgelegt werden

Einschränkungen

  1. Anpassen der Einschränkungen für UILabel LefMargin, RightMargin und Top Margin.

  2. Veränderung Content Compression Resistance Priority For Vertical = 1000` So dass Vertikal> Horizontal.

Einschränkungen von UILabel

Bearbeitet:

noOfLines=0

und die folgenden Einschränkungen reichen aus, um die gewünschten Ergebnisse zu erzielen.

Geben Sie hier die Bildbeschreibung ein


Das war großartig. Können Sie erklären, warum Vertikal> Horizontal den Job gemacht hat? Vielen Dank.
Gabriel

33

Erstellen Sie eine Unterklasse von UILabel. Klappt wunderbar:

// TopLeftLabel.h

#import <Foundation/Foundation.h>

@interface TopLeftLabel : UILabel 
{
}

@end

// TopLeftLabel.m

#import "TopLeftLabel.h"

@implementation TopLeftLabel

- (id)initWithFrame:(CGRect)frame 
{
    return [super initWithFrame:frame];
}

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines 
{
    CGRect textRect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];    
    textRect.origin.y = bounds.origin.y;
    return textRect;
}

-(void)drawTextInRect:(CGRect)requestedRect 
{
    CGRect actualRect = [self textRectForBounds:requestedRect limitedToNumberOfLines:self.numberOfLines];
    [super drawTextInRect:actualRect];
}

@end

Wie hier besprochen .


27

Ich habe eine util-Funktion geschrieben, um diesen Zweck zu erreichen. Sie können einen Blick darauf werfen:

// Passen Sie die Höhe eines mehrzeiligen Etiketts an, damit es vertikal zur Oberseite ausgerichtet wird
+ (void) alignLabelWithTop: (UILabel *) label {
  CGSize maxSize = CGSizeMake (label.frame.size.width, 999);
  label.adjustsFontSizeToFitWidth = NO;

  // tatsächliche Höhe ermitteln
  CGSize actualSize = [label.text sizeWithFont: label.font beschränkterToSize: maxSize lineBreakMode: label.lineBreakMode];
  CGRect rect = label.frame;
  rect.size.height = actualSize.height;
  label.frame = rect;
}}

.Wie benutzt man? (Wenn lblHello vom Interface Builder erstellt wird, überspringe ich einige Details zu UILabel-Attributen.)

lblHello.text = @ "Hallo Welt! Hallo Welt! Hallo Welt! Hallo Welt! Hallo Welt! Hallo Welt! Hallo Welt! Hallo Welt!";
lblHello.numberOfLines = 5;
[Utils alignLabelWithTop: lblHello];

Ich habe es auch in meinem Blog als Artikel geschrieben: http://fstoke.me/blog/?p=2819


27

Ich habe eine Weile gebraucht, um den Code sowie den Code auf der eingeführten Seite zu lesen, und festgestellt, dass alle versuchen, die Rahmengröße des Etiketts so zu ändern, dass die standardmäßige vertikale Ausrichtung in der Mitte nicht angezeigt wird.

In einigen Fällen möchten wir jedoch, dass die Beschriftung alle diese Leerzeichen belegt, auch wenn die Beschriftung so viel Text enthält (z. B. mehrere Zeilen mit gleicher Höhe).

Hier habe ich eine alternative Methode verwendet, um das Problem zu lösen, indem ich einfach Zeilenumbrüche an das Ende des Etiketts aufgefüllt habe (bitte beachten Sie, dass ich das tatsächlich geerbt habe UILabel, es aber nicht erforderlich ist):

CGSize fontSize = [self.text sizeWithFont:self.font];

finalHeight = fontSize.height * self.numberOfLines;
finalWidth = 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 "];
}

22

Was ich in meiner App getan habe, war, die Line-Eigenschaft des UILabels auf 0 zu setzen sowie eine untere Einschränkung des UILabels zu erstellen und sicherzustellen, dass es auf> = 0 gesetzt ist, wie in der Abbildung unten gezeigt. Geben Sie hier die Bildbeschreibung ein


19

Ich habe die Vorschläge hier aufgenommen und eine Ansicht erstellt, die ein UILabel umschließen kann, die Größe ändert und die Anzahl der Zeilen so einstellt, dass es oben ausgerichtet ist. Fügen Sie einfach ein UILabel als Unteransicht ein:

@interface TopAlignedLabelContainer : UIView
{
}

@end

@implementation TopAlignedLabelContainer

- (void)layoutSubviews
{
    CGRect bounds = self.bounds;

    for (UILabel *label in [self subviews])
    {
        if ([label isKindOfClass:[UILabel class]])
        {
            CGSize fontSize = [label.text sizeWithFont:label.font];

            CGSize textSize = [label.text sizeWithFont:label.font
                                     constrainedToSize:bounds.size
                                         lineBreakMode:label.lineBreakMode];

            label.numberOfLines = textSize.height / fontSize.height;

            label.frame = CGRectMake(0, 0, textSize.width,
                 fontSize.height * label.numberOfLines);
        }
    }
}

@end

19

Sie können TTTAttributedLabel verwenden , es unterstützt die vertikale Ausrichtung.

@property (nonatomic) TTTAttributedLabel* label;
<...>

//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;

16

Ich habe festgestellt, dass die Antworten auf diese Frage jetzt etwas veraltet sind. Fügen Sie sie daher für die Fans des automatischen Layouts hinzu.

Das automatische Layout macht dieses Problem ziemlich trivial. Angenommen, wir fügen das Etikett hinzu, UIView *viewwird der folgende Code dies erreichen:

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setText:@"Some text here"];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
[view addSubview:label];

[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:@{@"label": label}]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]" options:0 metrics:nil views:@{@"label": label}]];

Die Höhe intrinsicContentSizedes Etiketts wird automatisch berechnet (mithilfe des Etiketts) und das Etikett wird von Kante zu Kante horizontal oben auf dem Etikett positioniert view.


15

Ich habe viele der oben genannten Methoden verwendet und möchte nur einen schnellen und schmutzigen Ansatz hinzufügen, den ich verwendet habe:

myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];

Stellen Sie sicher, dass die Anzahl der Zeilenumbrüche in der Zeichenfolge dazu führt, dass Text den verfügbaren vertikalen Raum ausfüllt, und stellen Sie das UILabel so ein, dass überfließender Text abgeschnitten wird.

Weil manchmal gut genug gut genug ist .


Angesichts der unterschiedlichen Bildschirmgrößen von iOS-Geräten müsste dann eine variable Anzahl von '\ n' angegeben werden, um die Änderung der Höhe des Etiketts zu berücksichtigen (was eine Möglichkeit ist). Daher ist diese Methode auf lange Sicht nicht besonders nützlich.
Rambatino

Hinweis: "schnell und schmutzig", nicht "perfekte Lösung für alle Zeiten". Ich sag bloß'.
Code Roadie

2
@CodeRoadie Schnell und schmutzig hat der Trick für mich getan, ich hatte ein paar Layoutprobleme mit der richtigen Antwort. Ich könnte es "richtig" machen, aber danke, dass du mir etwas Zeit gespart hast!
Séraphin Hochart

@dGambit bitte beachten: "schnell und schmutzig "
Code Roadie

1
Beim dynamischen Laden von Ansichten habe ich kürzlich gelernt, UITextViewdass sie aufgerufen dlopenwerden können, um die Texteingabe zu unterstützen. Dies kann zu erheblichen Verzögerungen im UI-Thread führen, sodass dieser Ansatz viel leistungsfähiger ist!
Yano

14

Ich wollte ein Etikett, das mehrzeilig sein kann, eine minimale Schriftgröße aufweist und in der übergeordneten Ansicht sowohl horizontal als auch vertikal zentriert ist. Ich habe mein Etikett programmgesteuert zu meiner Ansicht hinzugefügt:

- (void) customInit {
    // Setup label
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    self.label.numberOfLines = 0;
    self.label.lineBreakMode = UILineBreakModeWordWrap;
    self.label.textAlignment = UITextAlignmentCenter;

    // Add the label as a subview
    self.autoresizesSubviews = YES;
    [self addSubview:self.label];
}

Und dann, als ich den Text meines Etiketts ändern wollte ...

- (void) updateDisplay:(NSString *)text {
    if (![text isEqualToString:self.label.text]) {
        // Calculate the font size to use (save to label's font)
        CGSize textConstrainedSize = CGSizeMake(self.frame.size.width, INT_MAX);
        self.label.font = [UIFont systemFontOfSize:TICKER_FONT_SIZE];
        CGSize textSize = [text sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        while (textSize.height > self.frame.size.height && self.label.font.pointSize > TICKER_MINIMUM_FONT_SIZE) {
            self.label.font = [UIFont systemFontOfSize:self.label.font.pointSize-1];
            textSize = [ticker.blurb sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        }
        // In cases where the frame is still too large (when we're exceeding minimum font size),
        // use the views size
        if (textSize.height > self.frame.size.height) {
            textSize = [text sizeWithFont:self.label.font constrainedToSize:self.frame.size];
        }

        // Draw 
        self.label.frame = CGRectMake(0, self.frame.size.height/2 - textSize.height/2, self.frame.size.width, textSize.height);
        self.label.text = text;
    }
    [self setNeedsDisplay];
}

Hoffe das hilft jemandem!


14

FXLabel (auf Github) erledigt dies sofort, indem es label.contentModeauf setzt UIViewContentModeTop. Diese Komponente wurde nicht von mir hergestellt, aber es ist eine Komponente, die ich häufig verwende, die über unzählige Funktionen verfügt und anscheinend gut funktioniert.


11

Wenn Sie dies lesen, weil der Text in Ihrem Etikett nicht vertikal zentriert ist, beachten Sie, dass einige Schriftarten nicht gleich gestaltet sind. Wenn Sie beispielsweise ein Etikett mit der Zapfino-Größe 16 erstellen, wird der Text nicht perfekt vertikal zentriert.

Wenn Sie jedoch mit helvetica arbeiten, wird Ihr Text vertikal zentriert.


Viele benutzerdefinierte Schriftarten sind nicht vertikal mittig ausgerichtet. UILabel oder UITextView sind immer vertikal mittig ausgerichtet. Bei der iOS-Programmierung müssen Sie nicht über die vertikale Ausrichtung nachdenken.
Amit Singh

11

Verwenden Sie textRect(forBounds:limitedToNumberOfLines:).

class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        super.drawText(in: textRect)
    }
}

Sie, mein Herr, sind ein Gott!
Diogo Antunes

1
Diese Antwort sollte viel mehr Stimmen bekommen , da es bei weitem die schönste und sauberste Lösung ist!
Michael Ochs

10

Unterklasse UILabel und schränken Sie das Zeichnungsrechteck wie folgt ein:

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

    [super drawTextInRect:rect];
}

Ich habe die Lösung mit Newline-Padding ausprobiert und bin in einigen Fällen auf ein falsches Verhalten gestoßen. Nach meiner Erfahrung ist es einfacher, die Zeichnung wie oben zu beschränken, als sich damit zu beschäftigen numberOfLines.

PS Sie können sich vorstellen, UIViewContentMode auf folgende Weise zu unterstützen:

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

10

Wenn Sie Autolayout verwenden, setzen Sie die vertikale contentHuggingPriority entweder in Code oder IB auf 1000. In IB müssen Sie dann möglicherweise eine Höhenbeschränkung entfernen, indem Sie ihre Priorität auf 1 setzen und sie dann löschen.


8

Solange Sie keine komplexe Aufgabe ausführen, können Sie UITextViewstattdessen verwenden UILabels.

Deaktivieren Sie den Bildlauf.

Wenn Sie möchten, dass der Text vollständig angezeigt wird, nur Benutzer sizeToFitund sizeThatFits:Methoden


8

In kurzer Zeit

let myLabel : UILabel!

Damit Ihr Text Ihres Etiketts auf den Bildschirm passt und sich oben befindet

myLabel.sizeToFit()

Damit Ihre Schriftart des Etiketts an die Breite des Bildschirms oder eine bestimmte Breite angepasst wird.

myLabel.adjustsFontSizeToFitWidth = YES

und etwas TextAlignment für Label:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified


Nur eine Änderung der Syntax von der alten Syntax von [myLabel sizeToFit]. Vielen Dank!
Velkoon

7

Dies ist eine alte Lösung. Verwenden Sie das Autolayout unter iOS> = 6

Meine Lösung:

  1. Linien selbst teilen (Einstellungen für Etikettenumbruch ignorieren)
  2. Zeichne selbst Linien (ignoriere die Ausrichtung der Etiketten)

@interface UITopAlignedLabel : UILabel

@end

@implementation UITopAlignedLabel

#pragma mark Instance methods

- (NSArray*)splitTextToLines:(NSUInteger)maxLines {
    float width = self.frame.size.width;

    NSArray* words = [self.text componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    NSMutableArray* lines = [NSMutableArray array];

    NSMutableString* buffer = [NSMutableString string];    
    NSMutableString* currentLine = [NSMutableString string];

    for (NSString* word in words) {
        if ([buffer length] > 0) {
            [buffer appendString:@" "];
        }

        [buffer appendString:word];

        if (maxLines > 0 && [lines count] == maxLines - 1) {
            [currentLine setString:buffer];
            continue;
        }

        float bufferWidth = [buffer sizeWithFont:self.font].width;

        if (bufferWidth < width) {
            [currentLine setString:buffer];
        }
        else {
            [lines addObject:[NSString stringWithString:currentLine]];

            [buffer setString:word];
            [currentLine setString:buffer];
        }
    }

    if ([currentLine length] > 0) {
        [lines addObject:[NSString stringWithString:currentLine]];
    }

    return lines;
}

- (void)drawRect:(CGRect)rect {
    if ([self.text length] == 0) {
        return;
    }

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, self.textColor.CGColor);
    CGContextSetShadowWithColor(context, self.shadowOffset, 0.0f, self.shadowColor.CGColor);

    NSArray* lines = [self splitTextToLines:self.numberOfLines];
    NSUInteger numLines = [lines count];

    CGSize size = self.frame.size;
    CGPoint origin = CGPointMake(0.0f, 0.0f);

    for (NSUInteger i = 0; i < numLines; i++) {
        NSString* line = [lines objectAtIndex:i];

        if (i == numLines - 1) {
            [line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeTailTruncation];            
        }
        else {
            [line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeClip];
        }

        origin.y += self.font.lineHeight;

        if (origin.y >= size.height) {
            return;
        }
    }
}

@end
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.