Wenn Sie ein mehrzeiliges Label (mit Zeilenumbruch auf Word Wrap) in eine Stapelansicht setzen, verliert das Label sofort den Zeilenumbruch und zeigt stattdessen den Etikettentext in einer Zeile an.
Warum geschieht dies und wie werden mehrzeilige Beschriftungen in einer Stapelansicht beibehalten?
Die richtige Antwort ist hier: https://stackoverflow.com/a/43110590/566360
UILabel
in ein UIView
(Editor -> Einbetten in -> Ansicht) ein UILabel
an das UIView
anzupassen (z. B. abschließender Speicherplatz, oberster Speicherplatz und führender Platz für Superview-Einschränkungen).Das UIStackView
dehnt das UIView
aus, um richtig zu passen, und das UIView
zwingt das UILabel
zu mehreren Zeilen.
Für eine horizontale Stapelansicht, die eine UILabel
als eine ihrer Ansichten hat, setzen Sie zunächst im Interface Builder label.numberOfLines = 0
. Dadurch sollte das Etikett mehr als eine Zeile haben. Dies funktionierte anfangs nicht für mich, als die Stack-Ansicht stackView.alignment = .fill
hatte. Damit dies funktioniert, setzen Sie einfach stackView.alignment = .center
. Die Beschriftung kann jetzt in der UIStackView
auf mehrere Zeilen erweitert werden.
Die Apple-Dokumentation sagt
Für alle Ausrichtungen außer der Füllungsausrichtung verwendet die Stapelansicht jede Die intrinsische Eigenschaft "Content Size" der geordneten Ansicht bei der Berechnung ihrer Größe senkrecht zur Achse des Stapels
Beachten Sie das Wort außer hier. Bei Verwendung von .fill
ändert sich die horizontale UIStackView
NICHT vertikal in der Größe der arrangierten Unteransichten.
multiLine
wachsen, wenn Sie keine feste Breite angeben. Wenn wir die Breite festlegen, wird die Linie in mehrere Zeilen unterteilt, wenn diese Breite erreicht ist.Wenn wir der Stack-Ansicht keine feste Breite geben, werden die Dinge mehrdeutig. Wie lange wächst die Stack-Ansicht mit der Beschriftung (wenn der Beschriftungswert dynamisch ist)?
Hoffe, das kann dein Problem beheben.
Das Folgende ist eine Playground-Implementierung eines mehrzeiligen Labels mit einem Zeilenumbruch in einer UIStackView
. Es ist nicht erforderlich, die Variable UILabel
in etwas einzubetten und wurde mit Xcode 9.2 und Swift 4 getestet. Ich hoffe, es ist hilfreich.
import UIKit
import PlaygroundSupport
let containerView = UIView()
containerView.frame = CGRect.init(x: 0, y: 0, width: 400, height: 500)
containerView.backgroundColor = UIColor.white
var label = UILabel.init()
label.textColor = .black
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "This is an example of sample text that goes on for a long time. This is an example of sample text that goes on for a long time."
let stackView = UIStackView.init(arrangedSubviews: [label])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .fill
containerView.addSubview(stackView)
stackView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
stackView.widthAnchor.constraint(equalTo: containerView.widthAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true
PlaygroundPage.current.liveView = containerView
UIStackView
, die aus mehrzeiligen UILabel
s mit automatischer Höhe besteht.Der Etikettenumbruch basiert auf der Breite der Stapelansicht und die Höhe der Stapelansicht basiert auf der Höhe des Etikettenumbruchs. (Bei diesem Ansatz müssen Sie die Beschriftungen nicht in UIView
einbetten.) (Swift 5, iOS 12.2)
// A vertical stackview with multiline labels and automatic height.
class ThreeLabelStackView: UIStackView {
let label1 = UILabel()
let label2 = UILabel()
let label3 = UILabel()
init() {
super.init(frame: .zero)
self.translatesAutoresizingMaskIntoConstraints = false
self.axis = .vertical
self.distribution = .fill
self.alignment = .fill
label1.numberOfLines = 0
label2.numberOfLines = 0
label3.numberOfLines = 0
label1.lineBreakMode = .byWordWrapping
label2.lineBreakMode = .byWordWrapping
label3.lineBreakMode = .byWordWrapping
self.addArrangedSubview(label1)
self.addArrangedSubview(label2)
self.addArrangedSubview(label3)
// (Add some test data, a little spacing, and the background color
// make the labels easier to see visually.)
self.spacing = 1
label1.backgroundColor = .orange
label2.backgroundColor = .orange
label3.backgroundColor = .orange
label1.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi."
label2.text = "Hello darkness my old friend..."
label3.text = "When I wrote the following pages, or rather the bulk of them, I lived alone, in the woods, a mile from any neighbor, in a house which I had built myself, on the shore of Walden Pond, in Concord, Massachusetts, and earned my living by the labor of my hands only."
}
required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
Hier ist ein Beispiel ViewController
, das es verwendet.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let myLabelStackView = ThreeLabelStackView()
self.view.addSubview(myLabelStackView)
// Set stackview width to its superview.
let widthConstraint = NSLayoutConstraint(item: myLabelStackView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.width, multiplier: 1, constant: 0)
self.view.addConstraints([widthConstraint])
}
}
Der Zaubertrick für mich bestand darin, eine widthAnchor
auf die UIStackView
zu setzen.
Die Einstellung von leadingAnchor
und trailingAnchor
funktioniert nicht, aber die Einstellung von centerXAnchor
und widthAnchor
hat die Anzeige der UILabel richtig gemacht.
Fügen Sie UIStackView
-Eigenschaften hinzu.
stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.spacing = 8.0
stackView.axis = .horizontal
Anstatt ein Label in UIView
hinzuzufügen, das nicht erforderlich ist. Wenn Sie in UITableViewCell
verwenden, laden Sie die Daten bei der Rotation erneut.
iOS 9+
Rufen Sie [textLabel sizeToFit]
auf, nachdem Sie den UILabel-Text festgelegt haben.
sizeToFit gestaltet das mehrzeilige Label mit PreferredMaxWidth neu. Das Label ändert die Größe der StackView, wodurch die Zelle verkleinert wird. Neben dem Fixieren der Stapelansicht mit der Inhaltsansicht sind keine zusätzlichen Einschränkungen erforderlich.
Das Setzen von preferredMaxLayoutWidth auf das UILabel hat für mich funktioniert
self.myLabel.preferredMaxLayoutWidth = self.bounds.size.width;
Das Systemlayout sollte Ursprung, Breite und Höhe bestimmen, um Unteransichten zu zeichnen. In diesem Fall haben alle Unteransichten die gleiche Priorität. Dies führt zu Konflikten. Das Layoutsystem kennt keine Abhängigkeiten zwischen den Ansichten, die man zuerst, dann und so weiter zeichnet
Wenn Sie die Komprimierung für Stapel-Unteransichten festlegen, wird das Problem mit mehreren Zeilen behoben. Dies hängt davon ab, ob die Stapelansicht horizontal oder vertikal ist und aus welcher mehrere Zeilen bestehen sollen. stackOtherSubviews .setContentCompressionResistancePriority(.defaultHight, for: .horizontal)
lblTitle.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
Es ist fast wie bei Andy's Answer, aber du kannst dein UILabel
in extra UIStackview
einfügen, vertikal hat für mich gearbeitet.
In meinem Fall folgte ich den vorherigen Vorschlägen, aber mein Text wurde immer noch auf eine einzige Zeile gekürzt, allerdings nur im Querformat. Es stellte sich heraus, dass ich im Text des Etiketts ein unsichtbares \0
-Nullzeichen gefunden habe, das der Täter war. Es muss neben dem Em-Strich-Symbol eingeführt worden sein, das ich eingefügt hatte. Um zu sehen, ob dies auch in Ihrem Fall der Fall ist, verwenden Sie den View Debugger, um Ihr Label auszuwählen und seinen Text zu überprüfen.
Was hat bei mir funktioniert?
stapelansicht: Ausrichtung: Füllen, Verteilen: Füllen, Beschränkung proportional Breite zum Sup. 0,8
beschriftung: Mitte und Zeilen = 0
Nachdem ich alle obigen Vorschläge ausprobiert hatte, stellte ich fest, dass für UIStackView keine Änderungen der Eigenschaften erforderlich sind. Ich ändere einfach die Eigenschaften der UILabels wie folgt (Die Beschriftungen werden bereits zu einer vertikalen Stapelansicht hinzugefügt):
Swift 4 Beispiel:
[titleLabel, subtitleLabel].forEach(){
$0.numberOfLines = 0
$0.lineBreakMode = .byWordWrapping
$0.setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
}
Xcode 9.2:
Legen Sie einfach die Anzahl der Zeilen auf 0 fest. Das Storyboard sieht nach der Einstellung seltsam aus. Mach dir keine Sorgen das Projekt auszuführen. Während der Ausführung wird alles entsprechend der Storyboard-Konfiguration angepasst. Ich denke, es ist ein Fehler im Storyboard .
Tipps: Legen Sie zuletzt "Liner-Nummer auf 0" fest. Setzen Sie sie zurück, wenn Sie eine andere Ansicht bearbeiten möchten, und setzen Sie sie nach der Bearbeitung auf 0.
Für alle, die es immer noch nicht schaffen. Versuchen Sie, Autoshrink mit einer minimalen Schriftgröße für dieses UILabel festzulegen.