wake-up-neo.net

UILabel sizeToFit funktioniert nicht mit Autolayout ios6

Wie soll ich programmgesteuert (und in welcher Methode) ein UILabel konfigurieren, dessen Höhe von seinem Text abhängt? Ich habe versucht, es mit einer Kombination aus Storyboard und Code einzurichten, jedoch ohne Erfolg. Jeder empfiehlt sizeToFit, während er lineBreakMode und numberOfLines setzt. Unabhängig davon, ob ich diesen Code in viewDidLoad:, viewDidAppear: oder viewDidLayoutSubviews eingebe, kann ich ihn nicht zum Laufen bringen. Entweder mache ich die Box für langen Text zu klein und wächst nicht, oder ich mache sie zu groß und verkleinere mich nicht.

148
circuitlego

Bitte beachten Sie, dass in den meisten Fällen die Lösung von Matt wie erwartet funktioniert. Wenn es für Sie nicht funktioniert, lesen Sie bitte weiter.

Um die Höhe der Etiketten automatisch zu ändern, müssen Sie folgende Schritte ausführen:

  1. Legen Sie Layoutbeschränkungen für das Etikett fest 
  2. Legen Sie die Höhenbeschränkung mit niedriger Priorität fest. Es sollte niedriger sein als ContentCompressionResistancePriority
  3. Set numberOfLines = 0
  4. Legen Sie ContentHuggingPriority höher als die Höhenpriorität der Beschriftung fest
  5. Legen Sie die VorzugsmethodeLayoutWidth für das Label fest. Dieser Wert wird vom Etikett verwendet, um die Höhe zu berechnen

Zum Beispiel:

self.descriptionLabel = [[UILabel alloc] init];
self.descriptionLabel.numberOfLines = 0;
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.preferredMaxLayoutWidth = 200;

[self.descriptionLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.descriptionLabel];

NSArray* constrs = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[descriptionLabel_]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)];
[self addConstraints:constrs];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[descriptionLabel_]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
[self.descriptionLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[descriptionLabel_([email protected])]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];

Interface Builder verwenden

  1. Richten Sie vier Einschränkungen ein. Die Höhenbeschränkung ist obligatorisch .enter image description here

  2. Gehen Sie dann zum Attributinspektor des Labels und setzen Sie die Anzahl der Zeilen auf 0 .enter image description here

  3. Gehen Sie zum Größeninspektor des Labels und erhöhen Sie die vertikale ContentHuggingPriority und die vertikale ContentCompressionResistancePriority.
    enter image description here

  4. Wählen Sie die Höhenbeschränkung aus und bearbeiten Sie sie.
    enter image description here

  5. Und verringern Sie die Priorität der Höhenbeschränkung.
    enter image description here

Genießen. :)

400

Wenn Sie in iOS 6 Autolayout verwenden, werden die Seiten (oder die Breite) und die Oberseite eines UILabels automatisch vertikal vergrößert und verkleinert, um sich an den Inhalt anzupassen, wobei überhaupt kein Code und kein Durcheinander mit seinem Inhalt vorhanden ist Kompressionswiderstand oder was auch immer. Es ist ganz einfach.

Setzen Sie in komplexeren Fällen einfach die Variable preferredMaxLayoutWidth des Labels.

In jedem Fall geschieht das Richtige automatisch.

61
matt

Obwohl die Frage programmgesteuert heißt, dasselbe Problem aufgetreten ist und ich lieber mit Interface Builder arbeite, dachte ich, es könnte nützlich sein, die vorhandenen Antworten mit einer Interface Builder-Lösung zu ergänzen. 

Als erstes vergessen Sie sizeToFit. Auto Layout wird dies in Ihrem Namen auf der Grundlage der Größe des Inhalts durchführen. 

Das Problem ist also, wie man mit Auto Layout ein Etikett an den Inhalt anpasst? Insbesondere - weil die Frage es erwähnt - die Höhe. Beachten Sie, dass die gleichen Prinzipien für die Breite gelten.

Beginnen wir mit einem Beispiel von UILabel, dessen Höhe auf 41px hoch eingestellt ist:

enter image description here

Wie Sie oben im Bildschirmgreifer sehen können, ist "This is my text" oben und unten aufgefüllt. Das ist ein Abstand zwischen der Höhe des UILabels und seinem Inhalt, dem Text.

Wenn wir die App im Simulator ausführen, sehen wir dasselbe:

enter image description here

Nun wählen wir das UILabel im Interface Builder aus und werfen einen Blick auf die Standardeinstellungen im Größeninspektor:

enter image description here

Beachten Sie die hervorgehobene Einschränkung oben. Das ist die Content Hugging Priority. Wie Erica Sadun es in dem ausgezeichneten iOS Auto Layout Demystified beschreibt, ist dies:

so wie eine Ansicht es bevorzugt, zusätzliche Füllungen um den Kerninhalt zu vermeiden

Für uns mit dem UILabel ist der Kern der Text.

Hier kommen wir zum Kern dieses grundlegenden Szenarios. Wir haben unserem Textlabel zwei Randbedingungen gegeben. Sie stehen in Konflikt. Man sagt "die Höhe muss 41 Pixel hoch sein". Der andere sagt "Umriss die Ansicht auf den Inhalt, sodass wir keine zusätzlichen Füllungen haben". In unserem Fall die Ansicht auf Text umschließen, sodass keine zusätzlichen Polsterungen vorhanden sind.

Mit Auto Layout und zwei verschiedenen Anweisungen, die verschiedene Aktionen ausführen, muss die Laufzeitumgebung die eine oder die andere auswählen. Beides kann es nicht. Das UILabel kann nicht beide 41 Pixel hoch sein, und hat keine Auffüllung. 

Die Art und Weise, wie dies gelöst wird, ist die Angabe der Priorität. Eine Anweisung muss eine höhere Priorität haben als die andere. Wenn beide Anweisungen unterschiedliche Dinge sagen und dieselbe Priorität haben, tritt eine Ausnahme auf.

Also lass es uns versuchen. Meine Höhenbeschränkung hat eine Priorität von 1000, was erforderlich ist. Die Inhaltshöhe der Inhalte beträgt 250, was schwach ist. Was passiert, wenn wir die Höhenbeschränkung auf 249 reduzieren?

enter image description here

Jetzt können wir sehen, wie die Magie beginnt. Versuchen wir es in der Sim:

enter image description here

Genial! Inhaltliche Umarmung erreicht. Nur weil die Höhenpriorität 249 geringer ist als die inhaltliche Priorität 250. Im Grunde sage ich "die hier angegebene Höhe ist weniger wichtig als die, die ich für die Inhaltsumrandung angegeben habe". So gewinnt der Inhalt, der umarmt.

In der unteren Zeile kann die Beschriftung an den Text angepasst werden, indem Sie einfach die Höhen- oder Breitenbeschränkung angeben und diese Priorität in Verbindung mit der Prioritätsbeschränkung für den Inhalt dieser Achse festlegen. 

Wird das Äquivalent für die Breite als Übung für den Leser tun!

40
Max MacLeod

Aufgefallen in IOS7 sizeToFit funktionierte auch nicht - vielleicht kann Ihnen die Lösung auch helfen

[textView sizeToFit];
[textView layoutIfNeeded];
7
Nick Wood

Ich denke, ich sollte einen Beitrag leisten, da ich eine Weile gebraucht habe, um die richtige Lösung zu finden:

  • Das Ziel ist, Auto Layout seine Arbeit erledigen zu lassen, ohne sizeToFit () aufzurufen. Wir werden dies tun, indem wir die richtigen Einschränkungen angeben:
  • Geben Sie in Ihrem UILabel die Beschränkungen für den oberen, unteren und führenden/nachlaufenden Raum an
  • Legen Sie die Zeilenanzahl-Eigenschaft auf 0 fest
  • Erhöhen Sie die Content-Hugging-Priorität auf 1000
  • Verringern Sie die Priorität der Inhaltskomprimierungsresistenz auf 500
  • Senken Sie die Priorität Ihrer unteren Container-Einschränkung auf 500

Im Grunde ist es so, dass Sie Ihrem UILabel mitteilen, dass es zwar eine feste Höhenbeschränkung hat, die Einschränkung jedoch brechen kann, um den Inhalt zu verkleinern, um den Inhalt zu umschließen (wenn Sie beispielsweise eine einzige Zeile haben), aber nicht brechen Sie die Einschränkung, um sie zu vergrößern.

4
ArturT

Eine weitere Option, um sicherzustellen, dass die PreferredMaxLayoutWidth der Beschriftung mit der Breite der Beschriftung übereinstimmt:

#import "MyLabel.h"

@implementation MyLabel

-(void)setBounds:(CGRect)bounds
{
    [super setBounds:bounds];

    // This appears to be needed for iOS 6 which doesn't seem to keep
    // label preferredMaxLayoutWidth in sync with its width, which 
    // means the label won't grow vertically to encompass its text if 
    // the label's width constraint changes.
    self.preferredMaxLayoutWidth = self.bounds.size.width;
}

@end
4
Monte Hurd

In meinem Fall habe ich eine UIView-Unterklasse erstellt, die ein UILabel (von unbekannter Länge) enthält. In iOS7 war der Code unkompliziert: Legen Sie die Einschränkungen fest, machen Sie sich keine Sorgen um den Inhalt oder um die Kompression, und alles funktioniert wie erwartet. 

In iOS6 wurde das UILabel jedoch immer auf eine einzige Zeile gekürzt. Keine der obigen Antworten funktionierte für mich. Die Einstellungen für Content-Hugging und Komprimierungswiderstand wurden ignoriert. Die einzige Lösung, die das Beschneiden verhinderte, bestand darin, einen PreferredMaxLayoutWidth auf dem Etikett anzugeben. Ich wusste jedoch nicht, wo die bevorzugte Breite eingestellt werden sollte, da die Größe der übergeordneten Ansicht unbekannt war (sie würde tatsächlich durch den Inhalt definiert). 

Endlich fand ich die Lösung hier . Da ich an einer benutzerdefinierten Ansicht arbeitete, konnte ich einfach die folgende Methode hinzufügen, um die bevorzugte Layoutbreite festzulegen, nachdem die Einschränkungen einmal berechnet wurden, und berechnet sie dann erneut:

- (void)layoutSubviews
{
    // Autolayout hack required for iOS6
    [super layoutSubviews];
    self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
    [super layoutSubviews];
}
3
sumizome

Ich habe UILabel programmgesteuert hinzugefügt, und in meinem Fall war das genug:

label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0
2
mixel

ich habe es mit xCode6 gelöst, indem Sie "Preferred Width" auf "Automatic" setzen und die Beschriftung oben, vorne und hinten anheften enter image description here

2
Kazzar
UIFont *customFont = myLabel.font;
CGSize size = [trackerStr sizeWithFont:customFont
                             constrainedToSize:myLabel.frame.size // the size here should be the maximum size you want give to the label
                                 lineBreakMode:UILineBreakModeWordWrap];
float numberOfLines = size.height / customFont.lineHeight;
myLabel.numberOfLines = numberOfLines;
myLabel.frame = CGRectMake(258, 18, 224, (numberOfLines * customFont.lineHeight));
0
Swati

Eine Lösung, die für mich funktioniert hat; Wenn Ihr UILabel eine feste Breite hat, ändern Sie die Einschränkung von constant = in constant <= in Ihrer Schnittstellendatei 

 enter image description here

0
Alex Brown

Ich bin auch mit einer UIView-Unterklasse auf dieses Problem gestoßen, die ein UILabel als eines seiner internen Elemente enthält. Selbst mit automatischem Layout und dem Ausprobieren aller empfohlenen Lösungen würde das Etikett die Höhe des Texts nur nicht verringern. In meinem Fall möchte ich nur, dass das Label eine Zeile ist.

Für mich hat es jedoch funktioniert, eine erforderliche Höhenbeschränkung für das UILabel hinzuzufügen und manuell auf die richtige Höhe einzustellen, wenn intrinsicContentSize aufgerufen wird. Wenn das UILabel nicht in einem anderen UIView enthalten ist, können Sie versuchen, UILabel zu subklassifizieren und eine ähnliche Implementierung bereitzustellen, indem Sie zuerst die Höhenbeschränkung festlegen und dann zurückkehren
[super instrinsicContentSize]; statt [self.containerview intrinsiceContentSize]; Ich mache unten, was spezifisch für meine UIView-Unterklasse ist.

- (CGSize)intrinsicContentSize
{
    CGRect expectedTextBounds = [self.titleLabel textRectForBounds:self.titleLabel.bounds limitedToNumberOfLines:1];
    self.titleLabelHeightConstraint.constant = expectedTextBounds.size.height;
    return [self.containerView intrinsicContentSize];

}

Funktioniert jetzt perfekt auf iOS 7 und iOS 8.

0
n8tr