Etichetta multilinea in UIStackView


154

Quando si inserisce un'etichetta multilinea (con l'interruzione di riga impostata su A capo automatico) in una vista pila, l'etichetta perde immediatamente l'interruzione di linea e visualizza invece il testo dell'etichetta in una riga.

Perché sta succedendo questo e come si conserva l'etichetta multilinea in una vista pila?


1
Hai impostato il numero di righe su 0?
dasdom,

Hai trovato una risposta?
Brenden,

Risposte:


204

La risposta corretta è qui:
https://stackoverflow.com/a/43110590/566360


  1. Incorpora l' UILabelinterno a UIView(Editor -> Incorpora in -> Visualizza)
  2. Utilizzare i vincoli per adattarli UILabelal UIView(ad esempio, spazio finale, spazio superiore e spazio iniziale per superare i vincoli)

Si UIStackViewestenderà UIViewper adattarsi correttamente e UIViewvincolerà UILabela più linee.


36
È così stupido ma funziona! Grazie uomo ! Forse un giorno Apple rilascerà qualcosa che non è mezzo rotto nel loro SDK ...
Guillaume L.,

1
Oddio! Sei un salvatore! Ci sono stato per ore :) Ricorda di impostare anche le linee su 0 in Attributes Inspector, mancava proprio questo.
absin

8
questa è soluzione alternativa, la soluzione corretta è qui stackoverflow.com/a/43110590/566360
vietstone

2
Mi è bastato solo cambiare l'allineamento orizzontale al centro. Non sono UIViewnecessari shenanigans.
shim

1
@Lucien questo è esattamente ciò che è stato detto in questa risposta. ma la risposta corretta è qui: stackoverflow.com/a/43110590/566360
Andy,

145

Per una vista stack orizzontale che ha UILabelcome una delle sue viste, in Interface Builder è innanzitutto impostato label.numberOfLines = 0. Ciò dovrebbe consentire all'etichetta di avere più di 1 riga. Questo inizialmente non ha funzionato per me quando la vista dello stack aveva stackView.alignment = .fill. Per farlo funzionare basta impostare stackView.alignment = .center. L'etichetta può ora espandersi su più righe all'interno di UIStackView.

La documentazione di Apple dice

Per tutti gli allineamenti ad eccezione dell'allineamento di riempimento, la vista pila utilizza la proprietà Dimensione contenuto intrinseca di ciascuna vista organizzata quando si calcola la sua dimensione perpendicolare all'asse della pila

Nota la parola tranne qui. Quando .fillviene utilizzato, l'orizzontale UIStackViewNON si ridimensiona verticalmente utilizzando le dimensioni delle visualizzazioni secondarie organizzate.


3
Questa è la soluzione corretta senza hack. Leggere i documenti paga sempre!
Islam Q.

3
Questa dovrebbe essere la soluzione accettata. Con la soluzione alternativa di UIView, il testo di UILabel galleggiava su un'altra sottoview nel mio caso.

14
In realtà non funziona ... Ho 3 etichette nel mio stackview. Ho impostato le linee a zero e l'allineamento al centro ... Sto ancora vedendo che le etichette sono tagliate.
MatterGoal

11
E 'la .alignmentdel UIStackView che si deve impostare a qualsiasi cosa, ma .fill non l'UILabel, che è un po' di confusione nell'esempio dato label.alignment = .center. Penso che dovrebbe esserestackView.alignment = .center
ae14,

2
Ma come posso far funzionare UILableView su più righe in StackView verticale?
DàChún,

42
  • Innanzitutto impostare il numero di etichetta delle righe su 0
  • La vista dello stack continuerà a non aumentare a multiLinemeno che non le si dia una larghezza fissa. Quando fissiamo la sua larghezza, si interrompe su multilinea quando viene raggiunta quella larghezza come mostrato:

registrazione dello schermo

Se non diamo una larghezza fissa alla vista dello stack, allora le cose diventano ambigue. Quanto tempo aumenterà la visualizzazione dello stack con l'etichetta (se il valore dell'etichetta è dinamico)?

Spero che questo possa risolvere il tuo problema.


3
Che cosa succede se la larghezza della vista dello stack non è fissa ma è proporzionale alla larghezza del dispositivo (ovvero della superview).
OutOnAWeekend,

Sì, possiamo avere anche una larghezza proporzionale. Il punto è se l'etichetta deve rompersi dopo una certa larghezza qualunque sia, ma deve essere definita.
Irfan,

@AnandKumar è possibile specificare preferredMaxLayoutWidthin viewDidLayoutSubviewsper l'etichetta in UIViewControllero in layoutSubviewsse sottoclasse UIView.
Shyngys Kassymov,

4
Questa avrebbe dovuto essere la risposta accettata, il punto centrale dello stackview è di non dover aggiungere vincoli tra lo stackview e i suoi elementi ...
Miele

4
Dare un valore fisso sconfigge lo scopo di autolayout
Islam Q.

17

Impostazione preferitaMaxLayoutWidth su UILabel ha funzionato per me

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

3
Questa è la risposta corretta nel mio libro. Ogni volta che si scherza con UILabel e è necessario gestire più linee, è necessario dargli un preferito MaxLayoutWidth. Potrebbe funzionare senza di essa, ma le cose possono diventare piuttosto funky molto rapidamente senza di essa.
Mof

2
Tutti hanno provato tutte le risposte e tutte erano sbagliate tranne la tua. Grazie!
levan

Questo ha risolto perfettamente il mio problema e sembra molto meno confuso, grazie.
Ethan Zhao,

Grazie per la tua risposta! Nel mio caso, l'allineamento di StackView era già impostato su .centere non avevo davvero bisogno della mia etichetta all'interno di UIView.
Fariza Zhumat,

12

Basta impostare il numero di righe su 0 nella finestra di ispezione Attributo per l'etichetta. Funzionerà per te.

inserisci qui la descrizione dell'immagine


12
Per uno stackView verticale, è necessario che la distribuzione sia impostata su "Fill" affinché funzioni.
Protocollo Snoopy,

2
L'impostazione della distribuzione su "Riempi" è la chiave per la correzione.
Dylan Moore,

Ho scoperto che per un UIStackView verticale, ho dovuto impostare i vincoli superiore e inferiore affinché un bambino UILabel si espandesse e mostrasse tutto il testo.
bruce1337

8

Dopo aver provato tutti i suggerimenti sopra riportati, ho riscontrato che non è necessario modificare le proprietà di UIStackView. Ho appena modificato le proprietà di UILabels come segue (Le etichette sono già state aggiunte a una vista pila verticale):

Esempio di Swift 4:

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

5

Il trucco magico per me è stato quello di impostare un widthAnchoral UIStackView.

L'impostazione leadingAnchore trailingAnchornon funzionerà, ma l'impostazione centerXAnchore widthAnchorla visualizzazione di UILabel verranno visualizzate correttamente.


4

iOS 9+

Chiama [textLabel sizeToFit]dopo aver impostato il testo di UILabel.

sizeToFit ridimensionerà l'etichetta multilinea usando la scelta preferita MaxLarghezza. L'etichetta ridimensionerà StackView, che ridimensionerà la cella. Non sono richiesti ulteriori vincoli oltre a fissare la vista dello stack alla vista del contenuto.


4

Ecco un esempio completo di una verticale UIStackViewcomposta da multilinea UILabelcon altezza automatica.

Le etichette si avvolgono in base alla larghezza dello stackview e l'altezza dello stackview si basa sull'altezza di avvolgimento dell'etichetta. (Con questo approccio non è necessario incorporare le etichette in a UIView.) (Swift 5, iOS 12.2)

inserisci qui la descrizione dell'immagine

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

Ecco un esempio ViewControllerche lo utilizza.

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

Aggiungi UIStackViewproprietà,

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

Invece di aggiungere un'etichetta all'interno UIViewche non è necessaria. Se si utilizza all'interno UITableViewCell, ricaricare i dati sulla rotazione.


3

Quella che segue è un'implementazione del Playground dell'etichetta multilinea con un'interruzione di riga all'interno di a UIStackView. Non richiede di incorporare UILabelnulla all'interno ed è stato testato con Xcode 9.2 e Swift 4. Spero sia utile.

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

1

Il layout del sistema dovrebbe capire l'origine, la larghezza e l'altezza per disegnarlo sottoview, in questo caso tutte le tue sottoview hanno la stessa priorità, quel punto crea conflitto, il sistema di layout non conosce dipendenze tra le viste, quale si disegna per prima, seconda e così via

Impostare la compressione delle sottoview dello stack risolverà il problema con più righe, a seconda che la visualizzazione dello stack sia orizzontale o verticale e quale si desidera diventare più righe. stackOtherSubviews .setContentCompressionResistancePriority(.defaultHight, for: .horizontal) lblTitle.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)


0

Nel mio caso, ho seguito i suggerimenti precedenti, ma il mio testo veniva comunque troncato su una sola riga sebbene solo in orizzontale. Risulta, ho trovato un \0carattere nullo invisibile nel testo dell'etichetta che era il colpevole. Deve essere stato introdotto accanto al simbolo del trattino che avevo inserito. Per vedere se ciò accade anche nel tuo caso, usa il Debugger Visualizza per selezionare l'etichetta e controllarne il testo.


0

Xcode 9.2:

Basta impostare il numero di righe su 0. Lo storyboard sembrerà strano dopo aver impostato questo. Non preoccuparti, esegui il progetto. Durante l'esecuzione tutto ridimensionerà in base alla configurazione dello storyboard. Penso che il suo tipo di bug nello storyboard. inserisci qui la descrizione dell'immagine

Suggerimenti: impostare "numero di linea su 0" nell'ultimo. ripristinalo quando desideri modificare un'altra vista e impostalo su 0 dopo la modifica.

inserisci qui la descrizione dell'immagine


0

Cosa ha funzionato per me!

stackview: allineamento: riempimento, distribuzione: riempimento, vincolo larghezza proporzionale a superview ex. 0.8,

etichetta: centro e linee = 0



0

È quasi come la risposta di @ Andy, ma puoi aggiungere il tuo UILabelin più UIStackview, verticale ha funzionato per me.


0

Per me, il problema era che l'altezza della vista dello stack era semplicemente troppo corta. L'etichetta e la vista dello stack sono state impostate correttamente per consentire all'etichetta di avere più linee, ma l'etichetta è stata la prima vittima della compressione del contenuto che la vista dello stack ha usato per ottenere la sua altezza abbastanza piccola.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.