Mehrzeiliges Label in UIStackView


154

Wenn Sie eine mehrzeilige Beschriftung (mit Zeilenumbruch auf Zeilenumbruch gesetzt) ​​in eine Stapelansicht einfügen, verliert die Beschriftung sofort den Zeilenumbruch und zeigt den Beschriftungstext stattdessen in einer Zeile an.

Warum passiert das und wie behält man ein mehrzeiliges Etikett in einer Stapelansicht bei?


1
Haben Sie die Anzahl der Zeilen auf 0 gesetzt?
Dasdom

Hast du eine Antwort gefunden?
Brenden

Antworten:


202

Die richtige Antwort finden Sie hier:
https://stackoverflow.com/a/43110590/566360


  1. Betten Sie das UILabelInnere ein UIView(Editor -> Einbetten -> Ansicht)
  2. Verwenden Sie Einschränkungen, um sie UILabelan die UIViewanzupassen (z. B. nachfolgender Bereich, oberer Bereich und führender Bereich, um Einschränkungen zu überwachen).

Das UIStackViewwird das ausdehnen, UIViewum richtig zu passen, und das UIViewwird das UILabelauf mehrere Linien beschränken.


35
Es ist so dumm, aber es funktioniert! Danke, Mann ! Vielleicht wird Apple eines Tages etwas veröffentlichen, das in seinem SDK nicht halb kaputt ist ...
Guillaume L.

1
Oh Mann! Du bist ein Retter! Ich war schon seit Stunden dabei :) Denken Sie daran, die Zeilen auch im Attributes Inspector auf 0 zu setzen, genau das fehlte.
Absin

7
Dies ist eine Problemumgehung. Die richtige Lösung finden Sie hier. stackoverflow.com/a/43110590/566360
vietstone

2
War für mich ausreichend, nur um die horizontale Ausrichtung auf Mitte zu ändern. Keine UIViewSpielereien nötig.
Shim

1
@ Lucien das ist genau das, was in dieser Antwort gesagt wurde. aber die richtige Antwort ist hier: stackoverflow.com/a/43110590/566360
Andy

143

Für eine horizontale Stapelansicht UILabelmit einer ihrer Ansichten wird zunächst im Interface Builder festgelegt label.numberOfLines = 0. Dies sollte ermöglichen, dass das Etikett mehr als eine Zeile enthält. Dies funktionierte anfangs nicht für mich, als die Stapelansicht hatte stackView.alignment = .fill. Damit es funktioniert, einfach einstellen stackView.alignment = .center. Die Beschriftung kann jetzt auf mehrere Zeilen innerhalb der Beschriftung erweitert werden UIStackView.

Die Apple-Dokumentation sagt

Für alle Ausrichtungen mit Ausnahme der Füllausrichtung verwendet die Stapelansicht die intrinsische Content Size-Eigenschaft jeder angeordneten Ansicht, wenn ihre Größe senkrecht zur Stapelachse berechnet wird

Beachten Sie das Wort außer hier. Bei .fillVerwendung UIStackViewändert sich die Größe der Horizontalen NICHT vertikal unter Verwendung der angeordneten Größen der Unteransichten.


3
Dies ist die richtige Lösung ohne Hacks. Das Lesen der Dokumente zahlt sich immer aus!
Islam Q.

3
Dies sollte die akzeptierte Lösung sein. Mit der UIView-Problemumgehung schwebte der Text von UILabel in meinem Fall über einer anderen Unteransicht.

14
Es funktioniert eigentlich nicht ... Ich habe 3 Etiketten in meiner Stapelansicht. Ich habe Linien auf Null und Ausrichtung auf Mitte gesetzt ... Ich sehe immer noch, dass die Etiketten ausgeschnitten sind.
MatterGoal

11
Es ist die .alignmentvon der UIStackView , dass Sie Satz zu etwas haben , aber .fill nicht die UILabel, die ein wenig in dem gegebenen Beispiel verwirrend ist label.alignment = .center. Ich denke, das sollte seinstackView.alignment = .center
ae14

2
Aber wie kann ich dafür sorgen, dass UILableView mit mehreren Zeilen in vertikalem StackView funktioniert?
DàChún

42
  • Setzen Sie zuerst die Anzahl der Zeilen auf 0
  • Die Stapelansicht wird nur dann vergrößert, multiLinewenn Sie ihr eine feste Breite geben. Wenn wir seine Breite festlegen, wird es mehrzeilig, wenn diese Breite wie gezeigt erreicht ist:

Bildschirmaufnahme

Wenn wir der Stapelansicht keine feste Breite geben, werden die Dinge mehrdeutig. Wie lange wächst die Stapelansicht mit dem Etikett (wenn der Etikettenwert dynamisch ist)?

Hoffe, dies kann Ihr Problem beheben.


3
Was ist, wenn die Breite der Stapelansicht nicht fest ist, sondern proportional zur Breite des Geräts (dh der Übersicht)?
OutOnAWeekend

Ja, wir können auch eine proportionale Breite haben. Der Punkt ist, wenn das Etikett nach einer gewissen Breite brechen muss, was auch immer es ist, aber definiert werden muss.
Irfan

@AnandKumar Sie angeben können , preferredMaxLayoutWidthin viewDidLayoutSubviewsfür das Etikett in UIViewControlleroder in , layoutSubviewswenn Sie eine Unterklasse UIView.
Shyngys Kassymov

4
Dies sollte die akzeptierte Antwort gewesen sein, der springende Punkt der Stapelansicht ist, keine Einschränkungen zwischen der Stapelansicht und ihren Elementen hinzufügen zu müssen ...
Honey

4
Wenn Sie einen festen Wert angeben, wird der Zweck des Autolayout
Islam Q.

17

Das Setzen von PreferredMaxLayoutWidth auf das UILabel hat bei mir funktioniert

self.myLabel.preferredMaxLayoutWidth = self.bounds.size.width;

3
Dies ist die richtige Antwort in meinem Buch. Wann immer Sie mit UILabels herumspielen und mehrere Zeilen verarbeiten müssen, müssen Sie ihr wirklich eine bevorzugte MaxLayoutWidth geben. Es könnte ohne es funktionieren, aber ohne es kann es sehr schnell ziemlich funky werden.
Mof

2
Alle haben alle Antworten ausprobiert und alle außer Ihren waren falsch. Vielen Dank!
Levan

Dies hat mein Problem perfekt gelöst und fühlt sich viel weniger hackig an, danke.
Ethan Zhao

Danke für deine Antwort! In meinem Fall war die Ausrichtung von stackView bereits eingestellt .centerund ich brauchte mein Label in UIView wirklich nicht.
Fariza Zhumat

12

Setzen Sie einfach die Anzahl der Zeilen im Attributinspektor für die Beschriftung auf 0. Es wird für Sie funktionieren.

Geben Sie hier die Bildbeschreibung ein


12
Für eine vertikale Stapelansicht muss die Verteilung auf "Füllen" eingestellt sein, damit dies funktioniert.
SnoopyProtocol

2
Das Setzen der Distribution auf "Fill" ist der Schlüssel für das Update.
Dylan Moore

Ich fand heraus, dass ich für eine vertikale UIStackView obere und untere Einschränkungen festlegen musste, damit ein untergeordnetes UILabel den gesamten Text erweitern und anzeigen kann.
Bruce1337

8

Nachdem ich alle oben genannten Vorschläge ausprobiert hatte, stellte ich fest, dass für UIStackView keine Änderung der Eigenschaften erforderlich ist. Ich ändere nur die Eigenschaften der UILabels wie folgt (Die Beschriftungen sind bereits einer vertikalen Stapelansicht hinzugefügt):

Swift 4 Beispiel:

    [titleLabel, subtitleLabel].forEach(){
        $0.numberOfLines = 0
        $0.lineBreakMode = .byWordWrapping
        $0.setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
    }

5

Der Zaubertrick für mich war, einen widthAnchorauf den zu setzen UIStackView.

Einstellung leadingAnchorund trailingAnchorfunktioniert nicht, aber Einstellung centerXAnchorund widthAnchorkorrekte Anzeige des UILabel.


4

iOS 9+

Rufen Sie an, [textLabel sizeToFit]nachdem Sie den Text des UILabels festgelegt haben.

sizeToFit gestaltet das mehrzeilige Etikett mit PreferredMaxWidth neu. Die Größe der Beschriftung ändert die Größe der Stapelansicht, wodurch die Größe der Zelle geändert wird. Neben dem Anheften der Stapelansicht an die Inhaltsansicht sind keine zusätzlichen Einschränkungen erforderlich.


4

Hier ist ein vollständiges Beispiel für eine Vertikale UIStackView, die aus mehrzeiligen UILabels mit automatischer Höhe besteht.

Der Etikettenumbruch basiert auf der Breite der Stapelansicht und die Höhe der Stapelansicht basiert auf der Umbruchhöhe des Etiketts. (Bei diesem Ansatz müssen Sie die Beschriftungen nicht in a einbetten UIView.) (Swift 5, iOS 12.2)

Geben Sie hier die Bildbeschreibung ein

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

3

Das Folgende ist eine Playground-Implementierung eines mehrzeiligen Etiketts mit einem Zeilenumbruch innerhalb von a UIStackView. Es erfordert keine Einbettung des UILabelInneren 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

2

UIStackViewEigenschaften hinzufügen ,

stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.spacing = 8.0
stackView.axis = .horizontal

Anstatt eine Beschriftung hinzuzufügen, UIViewdie nicht erforderlich ist. Wenn Sie eine Beschriftung verwenden UITableViewCell, laden Sie die Daten bei der Drehung neu.


1

Das Systemlayout sollte Ursprung, Breite und Höhe ermitteln, um Unteransichten zu zeichnen. In diesem Fall haben alle Ihre Unteransichten die gleiche Priorität. Dieser Punkt führt zu Konflikten. Das Layoutsystem kennt keine Abhängigkeiten zwischen Ansichten, die zuerst, zweitens usw. gezeichnet werden

Durch die Komprimierung der Stapel-Unteransichten wird das Problem mit mehreren Zeilen gelöst, je nachdem, ob Ihre Stapelansicht horizontal oder vertikal ist und welche mehrere Zeilen werden sollen. stackOtherSubviews .setContentCompressionResistancePriority(.defaultHight, for: .horizontal) lblTitle.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)


0

In meinem Fall folgte ich den vorherigen Vorschlägen, aber mein Text wurde immer noch auf eine einzelne Zeile gekürzt, allerdings nur im Querformat. Es stellte sich heraus, dass ich \0im Text des Etiketts ein unsichtbares Nullzeichen gefunden habe, das der Schuldige war. Es muss neben dem von mir eingefügten em-Strichsymbol eingefügt worden sein. Um festzustellen, ob dies auch in Ihrem Fall der Fall ist, wählen Sie mit dem View Debugger Ihr Etikett aus und überprüfen Sie dessen Text.


0

Xcode 9.2:

Setzen Sie einfach die Anzahl der Zeilen auf 0. Das Storyboard sieht nach dem Einstellen seltsam aus. Mach dir keine Sorgen, führe das Projekt aus. Während der Ausführung wird die Größe aller Elemente entsprechend Ihrem Storyboard-Setup geändert. Ich denke, es ist eine Art Fehler im Storyboard. Geben Sie hier die Bildbeschreibung ein

Tipps: Setzen Sie im letzten "Anzahl der Liner auf 0". Setzen Sie es zurück, wenn Sie eine andere Ansicht bearbeiten möchten, und setzen Sie es nach der Bearbeitung auf 0.

Geben Sie hier die Bildbeschreibung ein


0

Was hat bei mir funktioniert!

Stapelansicht: Ausrichtung: Füllung, Verteilung: Füllung, Einschränkung der proportionalen Breite zur Übersicht ex. 0,8,

label: center und lines = 0



0

Es ist fast wie bei @ Andy's Answer, aber Sie können Ihre UILabelzusätzliche UIStackview, vertikale Arbeit für mich hinzufügen .


0

Für mich war das Problem, dass die Höhe der Stapelansicht einfach zu kurz war. Das Etikett und die Stapelansicht wurden ordnungsgemäß eingerichtet, damit das Etikett mehrere Zeilen haben kann. Das Etikett war jedoch das erste Opfer der Inhaltskomprimierung, mit der die Stapelansicht ihre Höhe klein genug machte.

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.