it-swarm.com.de

iOS: Mehrzeiliges UILabel im automatischen Layout

Ich habe Probleme beim Versuch, mit dem automatischen Layout ein grundlegendes Layoutverhalten zu erzielen. Mein View Controller sieht in IB so aus:

enter image description here

Das obere Etikett ist das Titeletikett, ich weiß nicht, wie viele Zeilen es sein wird. Ich benötige die Titelbezeichnung, um alle Textzeilen anzeigen zu können. Ich brauche auch die beiden anderen Etiketten und das kleine Bild direkt unter dem Titel, wie groß es auch sein mag. Ich habe vertikale Abstandsbeschränkungen zwischen den Etiketten und dem kleinen Bild sowie eine obere Abstandsbeschränkung zwischen dem Titeletikett und seiner Übersicht und eine untere Abstandsbeschränkung zwischen dem kleinen Bild und seiner Übersicht festgelegt. Das weiße UIView hat keine Höhenbeschränkung, daher sollte es vertikal gestreckt werden, um seine Unteransichten zu enthalten. Ich habe die Zeilenanzahl für die Titelbezeichnung auf 0 gesetzt.

Wie kann ich die Größe des Titeletiketts an die Anzahl der für die Zeichenfolge erforderlichen Zeilen anpassen? Ich verstehe, dass ich setFrame-Methoden nicht verwenden kann, da ich das automatische Layout verwende. Und ich muss Auto-Layout verwenden, weil ich diese anderen Ansichten brauche, um unter der Titelbezeichnung zu bleiben (daher die Einschränkungen).

Wie kann ich das erreichen?

178
James Harpe

Verwenden Sie -setPreferredMaxLayoutWidth Für das UILabel und Autolayout sollte den Rest erledigen.

[label setPreferredMaxLayoutWidth:200.0];

Siehe ILabel-Dokumentation zu preferredMaxLayoutWidth .

Update:

Es muss nur die Einschränkung height im Storyboard auf Greater than or equal to Gesetzt werden, nicht die Einschränkung setPreferredMaxLayoutWidth.

249
mwhuss

Erweitern Sie die Zeilenanzahl Ihres Etikettensatzes auf 0 und, was noch wichtiger ist, die Höhe für das automatische Layout auf> = x. Das automatische Layout erledigt den Rest. Sie können auch Ihre anderen Elemente basierend auf dem vorherigen Element enthalten, um sie dann korrekt zu positionieren.

auto layout

210
Charlie Wu

Quelle: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

Eigeninhaltliche Größe von mehrzeiligem Text

Die inhaltliche Größe von UILabel und NSTextField ist für mehrzeiligen Text nicht eindeutig. Die Höhe des Texts hängt von der Breite der Linien ab, die beim Auflösen der Einschränkungen noch ermittelt werden muss. Um dieses Problem zu lösen, haben beide Klassen eine neue Eigenschaft mit dem Namen preferredMaxLayoutWidth, die die maximale Zeilenbreite für die Berechnung der inneren Inhaltsgröße angibt.

Da wir diesen Wert normalerweise nicht im Voraus kennen, müssen wir einen zweistufigen Ansatz wählen, um dies zu erreichen. Zuerst lassen wir das automatische Layout arbeiten, und dann verwenden wir den resultierenden Rahmen im Layoutdurchlauf, um die bevorzugte maximale Breite zu aktualisieren und das Layout erneut auszulösen.

- (void)layoutSubviews
{
    [super layoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [super layoutSubviews];
}

Der erste Aufruf von [super layoutSubviews] ist erforderlich, damit das Etikett seinen Rahmen erhält, während der zweite Aufruf erforderlich ist, um das Layout nach der Änderung zu aktualisieren. Wenn Sie den zweiten Aufruf auslassen, wird der Fehler "NSInternalInconsistencyException" angezeigt, da im Layoutdurchlauf Änderungen vorgenommen wurden, die eine Aktualisierung der Einschränkungen erfordern, das Layout jedoch nicht erneut ausgelöst wurde.

Wir können dies auch in einer Label-Unterklasse selbst tun:

@implementation MyLabel
- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = self.frame.size.width;
    [super layoutSubviews];
}
@end

In diesem Fall müssen wir nicht zuerst [super layoutSubviews] aufrufen, da wir beim Aufrufen von layoutSubviews bereits einen Rahmen auf dem Etikett selbst haben.

Um diese Anpassung von der View Controller-Ebene aus vorzunehmen, schließen wir uns viewDidLayoutSubviews an. Zu diesem Zeitpunkt sind die Frames des ersten Auto-Layout-Durchgangs bereits festgelegt, und wir können sie verwenden, um die bevorzugte maximale Breite festzulegen.

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

Stellen Sie schließlich sicher, dass Sie keine explizite Größenbeschränkung für das Etikett haben, die eine höhere Priorität als die Priorität für die Inhaltskomprimierungsbeständigkeit des Etiketts hat. Andernfalls wird die berechnete Höhe des Inhalts übertroffen. Stellen Sie sicher, dass Sie alle Einschränkungen überprüfen, die sich auf die Höhe des Etiketts auswirken können.

44
Anton Matosov

Ich kämpfte nur mit genau diesem Szenario, aber mit einigen weiteren Ansichten, die nach Bedarf angepasst und nach unten verschoben werden mussten. Es hat mich verrückt gemacht, aber ich habe es endlich herausgefunden.

Hier ist der Schlüssel: Interface Builder zieht gerne zusätzliche Einschränkungen in Betracht, wenn Sie Ansichten hinzufügen und verschieben, und Sie bemerken dies möglicherweise nicht. In meinem Fall hatte ich eine Ansicht auf halber Strecke, die eine zusätzliche Einschränkung aufwies, die die Größe zwischen ihr und ihrer Übersicht spezifizierte und sie im Grunde auf diesen Punkt festlegte. Das bedeutete, dass nichts darüber die Größe verändern konnte, da dies dieser Einschränkung zuwiderlaufen würde.

Eine einfache Möglichkeit, um festzustellen, ob dies der Fall ist, besteht darin, die Größe des Etiketts manuell zu ändern. Lässt IB Sie wachsen? Wenn dies der Fall ist, verschieben sich die unten stehenden Beschriftungen wie erwartet? Stellen Sie sicher, dass Sie beide Kontrollkästchen aktiviert haben, bevor Sie die Größe ändern, um zu sehen, wie Ihre Einschränkungen Ihre Ansichten verschieben:

IB Menu

Wenn die Ansicht nicht mehr reagiert, befolgen Sie die Ansichten, die sich darunter befinden, und vergewissern Sie sich, dass in einer der Ansichten kein Platz vorhanden ist, um die Einschränkung zu überblicken. Vergewissern Sie sich dann, dass die Option für die Anzahl der Zeilen für das Etikett auf 0 gesetzt ist, und kümmern Sie sich um den Rest.

16
Cory Imdieke

Ich finde, Sie brauchen Folgendes:

  • Eine Top-Einschränkung
  • Eine führende Einschränkung (zB linke Seite)
  • Eine nachfolgende Einschränkung (z. B. rechte Seite)
  • Stellen Sie die Priorität für das Umarmen von Inhalten horizontal auf niedrig ein, damit der angegebene Bereich ausgefüllt wird, wenn der Text kurz ist.
  • Stellen Sie den Widerstand gegen Inhaltskomprimierung horizontal auf niedrig ein, damit der Inhalt umbrochen wird, anstatt zu versuchen, breiter zu werden.
  • Setzen Sie die Anzahl der Zeilen auf 0.
  • Setzen Sie den Zeilenumbruchmodus auf Zeilenumbruch.
5
Chris

Keine der verschiedenen Lösungen, die in den vielen Themen zu diesem Thema gefunden wurden, hat in meinem Fall perfekt funktioniert (x dynamische mehrzeilige Beschriftungen in dynamischen Tabellenzellen).

Ich habe einen Weg gefunden, es zu tun:

Nachdem Sie die Einschränkungen für Ihr Etikett festgelegt und die Eigenschaft multiline auf 0 gesetzt haben, erstellen Sie eine Unterklasse von UILabel. Ich habe mein AutoLayoutLabel angerufen:

@implementation AutoLayoutLabel

- (void)layoutSubviews{
    [self setNeedsUpdateConstraints];
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}

@end
0
Tanguy G.

Ich habe eine UITableViewCell mit einem Textumbruch. Ich habe wie folgt mit Textumbruch gearbeitet.

1) Legen Sie die UILabel-Einschränkungen wie folgt fest.

enter image description here

2) Set Nr. von Zeilen auf 0.

3) UITableViewCell wurde um die UILabel-Höhenbeschränkung erweitert.

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) Auf UITableViewCell:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5
0
A.G