Etykieta wielowierszowa w UIStackView

154

Podczas umieszczania etykiety wielowierszowej (z podziałem wiersza ustawionym na Zawijanie wierszy) w widoku stosu, etykieta natychmiast traci podział wiersza i zamiast tego wyświetla tekst etykiety w jednym wierszu.

Dlaczego tak się dzieje i jak można zachować etykietę wielowierszową w widoku stosu?

Dar
źródło
1
Czy ustawiłeś liczbę linii na 0?
dasdom
Znalazłeś odpowiedź?
Brenden

Odpowiedzi:

204

Prawidłowa odpowiedź jest tutaj:
https://stackoverflow.com/a/43110590/566360


  1. Osadź UILabelwnętrze UIView(Edytor -> Osadź w -> Widok)
  2. Użyj ograniczeń, aby dopasować UILabeldo UIView(na przykład spacja końcowa, spacja górna i spacja wiodąca do ograniczeń superwiewu)

UIStackViewBędzie wyciagnac UIViewaby prawidłowo dopasować i UIViewograniczy UILabeldo wielu linii.

Andy
źródło
36
To takie głupie, ale działa! Dzięki ! Może pewnego dnia Apple wyda coś, co nie jest w połowie zepsute w ich SDK ...
Guillaume L.
1
O stary! Jesteś zbawicielem! Byłem nad tym godzinami :) Pamiętaj, aby ustawić linie na 0 w Attributes Inspector, brakowało tylko tego.
absin
8
to jest obejście, prawidłowe rozwiązanie jest tutaj stackoverflow.com/a/43110590/566360
vietstone
2
Wystarczyło mi tylko zmienić wyrównanie poziome na środek. Żadne UIViewoszustwa nie są konieczne.
podkładka
1
@Lucien dokładnie to zostało powiedziane w tej odpowiedzi. ale prawidłowa odpowiedź jest tutaj: stackoverflow.com/a/43110590/566360
Andy,
144

W przypadku poziomego widoku stosu, który ma UILabeljako jeden z widoków, należy najpierw ustawić w programie Interface Builder label.numberOfLines = 0. Powinno to pozwolić, aby etykieta miała więcej niż 1 linię. Początkowo nie działało to dla mnie, gdy działał widok stosu stackView.alignment = .fill. Aby to działało, wystarczy ustawić stackView.alignment = .center. Etykieta może teraz rozszerzać się do wielu wierszy w pliku UIStackView.

Dokumentacja Apple mówi

W przypadku wszystkich linii trasowania z wyjątkiem wyrównania wypełnienia, widok stosu używa wewnętrznej właściwości Content Size każdego ułożonego widoku podczas obliczania rozmiaru prostopadłego do osi stosu

Zwróć uwagę na słowo z wyjątkiem tutaj. Gdy .filljest używany, UIStackViewrozmiar poziomy NIE zmienia się w pionie przy użyciu rozmieszczonych rozmiarów widoków podrzędnych.

pbm
źródło
3
To jest właściwe rozwiązanie bez hacków. Czytanie dokumentów zawsze się opłaca!
Islam Q.
3
To powinno być przyjęte rozwiązanie. Z obejściem UIView tekst UILabel unosił się nad innym podziałem w moim przypadku.
14
Właściwie to nie działa ... Mam 3 etykiety w moim widoku stosu. Ustawiłem linie na zero i wyrównanie do środka ... Nadal widzę, że etykiety są wycięte.
MatterGoal
11
Jest to .alignmentUIStackView, który musisz ustawić na cokolwiek, ale .fill nie UILabel, co w podanym przykładzie jest trochę zagmatwane label.alignment = .center. Myślę, że to powinno byćstackView.alignment = .center
ae14
2
Ale jak mogę sprawić, aby wiele wierszy UILableView działało w pionowym StackView?
DàChún
42
  • Najpierw ustaw liczbę wierszy etykiety na 0
  • Widok stosu nadal nie wzrośnie do, multiLinechyba że nadasz mu stałą szerokość. Kiedy ustalamy jego szerokość, łamie się do multilinii, gdy ta szerokość zostanie osiągnięta, jak pokazano:

nagrywanie ekranu

Jeśli nie damy stałej szerokości w widoku stosu, sprawy staną się niejednoznaczne. Jak długo widok stosu będzie się powiększał wraz z etykietą (jeśli wartość etykiety jest dynamiczna)?

Mam nadzieję, że to rozwiąże problem.

Irfan
źródło
3
A co, jeśli szerokość widoku stosu nie jest stała, ale zamiast tego jest proporcjonalna do szerokości urządzenia (tj. Nadzoru).
OutOnAWeekend
Tak, możemy mieć również proporcjonalną szerokość. Chodzi o to, czy etykieta ma się łamać po pewnej szerokości, niezależnie od tego, jaka jest, ale musi zostać zdefiniowana.
Irfan
@AnandKumar możesz określić preferredMaxLayoutWidthw viewDidLayoutSubviewsdla swojej etykiety w UIViewControllerlub w layoutSubviewspodklasie UIView.
Shyngys Kassymov
4
To powinna być akceptowana odpowiedź, cały punkt widoku stosu polega na tym, aby nie musieć dodawać ograniczeń między widokiem stosu a jego elementami ...
Honey
4
Podanie stałej wartości jest sprzeczne z celem autoukładu
Islam Q.
17

Ustawienie preferowanegoMaxLayoutWidth na UILabel zadziałało

self.myLabel.preferredMaxLayoutWidth = self.bounds.size.width;
Pablo Martinez
źródło
3
To jest poprawna odpowiedź w mojej książce. Kiedy kiedykolwiek zadzierasz z UILabel i potrzebujesz obsługiwać wiele linii, naprawdę musisz nadać mu preferowaną szerokośćMaxLayoutWidth. Może działać bez niego, ale bez niego rzeczy mogą się bardzo szybko stać.
Poniedziałek
2
Wszyscy wypróbowali wszystkie odpowiedzi i wszystkie były błędne, z wyjątkiem twojego. Dzięki!
lewan
To doskonale rozwiązało mój problem i wydaje się znacznie mniej hakerskie, dziękuję.
Ethan Zhao,
Dziękuję za odpowiedź! W moim przypadku wyrównanie mojego stackView było już ustawione na .centeri naprawdę nie potrzebowałem mojej etykiety w UIView.
Fariza Zhumat
12

Po prostu ustaw liczbę wierszy na 0 w Inspektorze atrybutów dla etykiety. To zadziała dla Ciebie.

wprowadź opis obrazu tutaj

technerd
źródło
12
Aby uzyskać pionowy stackView, musisz ustawić Distribution na „Fill”, aby to zadziałało.
SnoopyProtocol
2
Ustawienie dystrybucji na „Wypełnij” jest kluczem do poprawki.
Dylan Moore
Zauważyłem, że w przypadku UIStackView w pionie muszę ustawić górne i dolne ograniczenia, aby element podrzędny UILabel rozszerzał i wyświetlał cały tekst.
bruce1337
8

Po wypróbowaniu wszystkich powyższych sugestii stwierdziłem, że UIStackView nie wymaga zmiany właściwości. Po prostu zmieniam właściwości etykiet UIL w następujący sposób (etykiety są już dodane do widoku stosu pionowego):

Przykład języka Swift 4:

    [titleLabel, subtitleLabel].forEach(){
        $0.numberOfLines = 0
        $0.lineBreakMode = .byWordWrapping
        $0.setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
    }
Bill Chan
źródło
5

Magiczna sztuczka polegała na ustawieniu a widthAnchornaUIStackView .

Ustawienie leadingAnchori trailingAnchornie zadziała, ale ustawienie centerXAnchori widthAnchorsprawiło, że UILabel wyświetla się poprawnie.

Skoua
źródło
4

iOS 9+

Zadzwoń [textLabel sizeToFit]po ustawieniu tekstu UILabel.

sizeToFit zmieni układ etykiety wielowierszowej przy użyciu preferowanegoMaxWidth. Etykieta zmieni rozmiar stackView, co spowoduje zmianę rozmiaru komórki. Nie są wymagane żadne dodatkowe ograniczenia poza przypinaniem widoku stosu do widoku zawartości.

aumansoftware
źródło
4

Oto pełny przykład pionu UIStackViewzłożonego z multilinii UILabelz automatyczną wysokością.

Etykiety zawijane są na podstawie szerokości widoku stosu, a wysokość widoku stosu jest określana na podstawie zawiniętej wysokości etykiety. (Dzięki temu podejściu nie musisz osadzać etykiet w a UIView.) (Swift 5, iOS 12.2)

wprowadź opis obrazu tutaj

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

Oto próbka, ViewControllerktóra go używa.

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])
    }
}
zekel
źródło
3

Dodaj UIStackViewwłaściwości,

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

Zamiast dodawać etykietę w środku, UIViewktóra nie jest wymagana.Jeśli używasz w środku UITableViewCell, przeładuj dane o rotacji.

Sagar Daundkar
źródło
3

Poniżej przedstawiono implementację etykiety wieloliniowej Playground z podziałem wiersza wewnątrz UIStackView. Nie wymaga osadzania UILabelniczego w środku i został przetestowany z Xcode 9.2 i Swift 4. Mam nadzieję, że jest pomocny.

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
JaredH
źródło
1

Układ systemu powinien określać początek, szerokość i wysokość, aby narysować podglądy, w tym przypadku wszystkie Twoje podglądy mają ten sam priorytet, ten punkt powoduje konflikt, system układu nie zna zależności między widokami, który z nich rysuje pierwszy, drugi itd.

Kompresja set stack subviews rozwiąże problem z wieloma liniami, w zależności od tego, czy twój widok stosu jest poziomy czy pionowy i który z nich ma być wieloma liniami. stackOtherSubviews .setContentCompressionResistancePriority(.defaultHight, for: .horizontal) lblTitle.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

Trung Phan
źródło
0

W moim przypadku postępowałem zgodnie z poprzednimi sugestiami, ale mój tekst nadal był skracany do jednej linii, choć tylko w orientacji poziomej. Okazuje się, że znalazłem niewidoczny \0znak zerowy w tekście etykiety, który był winowajcą. Musiało być wprowadzone obok symbolu myślnika, który wstawiłem. Aby sprawdzić, czy dzieje się tak również w Twoim przypadku, użyj narzędzia View Debugger, aby wybrać etykietę i sprawdzić jej tekst.

Jordan H.
źródło
0

Xcode 9.2:

Po prostu ustaw liczbę linii na 0. Storyboard będzie wyglądał dziwnie po ustawieniu tego. Nie martw się, uruchom projekt. Podczas uruchamiania wszystko zmieni rozmiar zgodnie z konfiguracją scenorysu. Myślę, że to rodzaj błędu w scenorysie. wprowadź opis obrazu tutaj

Wskazówki: Ustaw „liczbę wkładek na 0” w ostatniej. zresetuj go, jeśli chcesz edytować inny widok i ustaw na 0 po edycji.

wprowadź opis obrazu tutaj

Surendra Kumar
źródło
0

Co mi pomogło!

widok stosu: wyrównanie: wypełnienie, dystrybucja: wypełnienie, proporcjonalna szerokość ograniczenia do nadzoru np. 0,8,

label: center i lines = 0

Michał Ziobro
źródło
0

Dla każdego, kto nadal nie może tego zrobić. Spróbuj ustawić Autoshrink z minimalną skalą czcionki na tym UILabel.

Zrzut ekranu Ustawienia automatycznego skurczu UILabel

Michal Mondík
źródło
Rozważ poprawienie swojej odpowiedzi na przykładzie kodu.
piątek
1
@fridoo Dodano zrzut ekranu ustawień.
Michal Mondík
0

To prawie jak odpowiedź @ Andy'ego, ale możesz dodać swoją UILabeldodatkową UIStackview, pionową pracę dla mnie.

Zaporozhchenko Oleksandr
źródło
0

Dla mnie problem polegał na tym, że wysokość widoku stosu była po prostu za mała. Etykieta i widok stosu zostały prawidłowo skonfigurowane, aby umożliwić etykietę składającą się z wielu wierszy, ale etykieta była pierwszą ofiarą kompresji treści, której użył widok stosu, aby uzyskać wystarczająco małą wysokość.

Łukasz
źródło