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.
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:
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
Richten Sie vier Einschränkungen ein. Die Höhenbeschränkung ist obligatorisch .
Gehen Sie dann zum Attributinspektor des Labels und setzen Sie die Anzahl der Zeilen auf 0 .
Gehen Sie zum Größeninspektor des Labels und erhöhen Sie die vertikale ContentHuggingPriority und die vertikale ContentCompressionResistancePriority.
Wählen Sie die Höhenbeschränkung aus und bearbeiten Sie sie.
Und verringern Sie die Priorität der Höhenbeschränkung.
Genießen. :)
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.
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:
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:
Nun wählen wir das UILabel im Interface Builder aus und werfen einen Blick auf die Standardeinstellungen im Größeninspektor:
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?
Jetzt können wir sehen, wie die Magie beginnt. Versuchen wir es in der Sim:
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!
Aufgefallen in IOS7 sizeToFit funktionierte auch nicht - vielleicht kann Ihnen die Lösung auch helfen
[textView sizeToFit];
[textView layoutIfNeeded];
Ich denke, ich sollte einen Beitrag leisten, da ich eine Weile gebraucht habe, um die richtige Lösung zu finden:
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.
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
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];
}
Ich habe UILabel
programmgesteuert hinzugefügt, und in meinem Fall war das genug:
label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0
ich habe es mit xCode6 gelöst, indem Sie "Preferred Width" auf "Automatic" setzen und die Beschriftung oben, vorne und hinten anheften
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));
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.