web-dev-qa-db-fra.com

Label multiligne dans UIStackView

Lorsque vous placez une étiquette multiligne (avec le saut de ligne défini sur Retour à la ligne) dans une vue de pile, l'étiquette perd immédiatement le saut de ligne et affiche le texte de l'étiquette sur une ligne.

Pourquoi cela se produit-il et comment conserver une étiquette multiligne dans une vue de pile? 

87
Boon

La bonne réponse est ici: https://stackoverflow.com/a/43110590/566360

  1. Incorporer la UILabel dans une UIView (Éditeur -> Incorporer dans -> Afficher)
    1. Utilisez des contraintes pour adapter la UILabel à la UIView (par exemple, les espaces de fin, de début et de début d'espace entre les contraintes).

La UIStackView étendra la UIView pour s’ajuster correctement et la UIView contraindra la UILabel à plusieurs lignes.

125
Andy

Pour une vue de pile horizontale ayant une UILabel parmi ses vues, dans Interface Builder, commencez par définir label.numberOfLines = 0. Cela devrait permettre à l’étiquette d’avoir plus d’une ligne. Au début, cela ne fonctionnait pas pour moi lorsque la vue de la pile contenait stackView.alignment = .fill. Pour que cela fonctionne, il suffit de définir stackView.alignment = .center. L'étiquette peut maintenant être étendue à plusieurs lignes dans la variable UIStackView.

La documentation Apple dit 

Pour tous les alignements sauf l'alignement de remplissage, la vue de pile utilise chacun propriété intrinsèque de la taille du contenu de la vue arrangée lors du calcul de son taille perpendiculaire à l’axe de la pile

Notez le mot sauf ici. Lorsque .fill est utilisé, la variable UIStackView horizontale ne se redimensionne PAS d'elle-même à l'aide des tailles de sous-vues organisées.

52
pbm
  • Commencez par définir le nombre de lignes de l'étiquette sur 0
  • La vue de pile ne grandira toujours pas à multiLine à moins que vous ne lui donniez une largeur fixe. Lorsque nous fixons sa largeur, il se brise en multiligne lorsque cette largeur est atteinte comme indiqué:

 screen recording

Si nous ne donnons pas une largeur fixe à la vue de la pile, les choses deviennent ambiguës. Combien de temps la vue de pile grandira-t-elle avec l'étiquette (si la valeur de l'étiquette est dynamique)?

J'espère que cela peut résoudre votre problème.

40
Irfan

Il suffit de définir le nombre de lignes à 0 dans l’inspecteur d’attributs pour l’étiquette. Cela fonctionnera pour vous.

 enter image description here

11
technerd

Ce qui suit est une implémentation Playground d’une étiquette multiligne avec un saut de ligne dans une UIStackView. Il ne nécessite aucune intégration de la variable UILabel et a été testé avec Xcode 9.2 et Swift 4. J'espère que cela vous sera 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
3
JaredH

Voici un exemple complet de UIStackView verticale composée de UILabels multiligne à hauteur automatique.

L'enveloppement des étiquettes en fonction de la largeur de la vue pile et de la hauteur de la vue pile est basé sur la hauteur enveloppée de l'étiquette. (Avec cette approche, vous n'avez pas besoin d'intégrer les étiquettes dans un UIView.) (Swift 5, iOS 12.2)

enter image description here

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

Voici un exemple ViewController qui l'utilise.

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])
    }
}
2
zekel

Le tour de magie pour moi consistait à définir widthAnchor sur UIStackView.

Définir leadingAnchor et trailingAnchor ne fonctionnera pas, mais régler centerXAnchor et widthAnchor a fait afficher UILabel correctement.

2
Skoua

Ajouter des propriétés UIStackView,

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

Au lieu d’ajouter une étiquette à l’intérieur de UIView qui n’est pas obligatoire. Si vous utilisez à l'intérieur de UITableViewCell, veuillez recharger les données en rotation.

2
Sagar Daundkar

iOS 9+ 

Appelez [textLabel sizeToFit] après avoir défini le texte de UILabel. 

sizeToFit repositionnera l'étiquette multiligne en utilisant preferredMaxWidth. L'étiquette redimensionnera la pile, ce qui redimensionnera la cellule. Aucune contrainte supplémentaire à part l'épinglage de la vue de pile à la vue de contenu n'est requise.

1
aumansoftware

Définir preferredMaxLayoutWidth sur UILabel a fonctionné pour moi

self.myLabel.preferredMaxLayoutWidth = self.bounds.size.width;
1
Pablo Martinez

C'est presque comme @ Andy's Answer, mais vous pouvez ajouter votre UILabel en extra UIStackview, la verticale a fonctionné pour moi.

0

Dans mon cas, j'ai suivi les suggestions précédentes, mais mon texte était toujours tronqué en une seule ligne, mais uniquement en mode paysage. Il s'avère que j'ai trouvé un caractère invisible \0 null dans le texte de l'étiquette, qui était le coupable. Il doit avoir été introduit à côté du symbole em dash que j'avais inséré. Pour voir si cela se produit également dans votre cas, utilisez le débogueur de vue pour sélectionner votre étiquette et inspecter son texte.

0
Jordan H

Ce qui a fonctionné pour moi!

stackview: alignement: remplissage, distribution: remplissage, contrainte largeur proportionnelle à superview ex. 0,8 

étiquette: centre et lignes = 0

0
Michał Ziobro

Après avoir essayé toutes les suggestions ci-dessus, je n’ai trouvé aucun changement de propriété nécessaire pour UIStackView. Je viens de modifier les propriétés des étiquettes UIL comme suit (les étiquettes sont déjà ajoutées à une vue de pile verticale):

Exemple de Swift 4:

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

Xcode 9.2:

Définissez simplement le nombre de lignes sur 0. Storyboard aura l’air bizarre une fois que vous aurez défini ceci. Ne vous inquiétez pas, lancez le projet. En cours d'exécution, tout sera redimensionné en fonction de la configuration de votre storyboard. Je pense que son genre de bug dans le storyboard .  enter image description here

Conseils: Définissez "nombre de doublure sur 0" dans la dernière. réinitialisez-le lorsque vous souhaitez modifier une autre vue et définissez-le sur 0 après modification.

 enter image description here

0
Surendra Kumar

Pour quiconque ne peut toujours pas le faire fonctionner. Essayez de définir Autoshrink avec une échelle de police minimale sur ce UILabel.

Paramètres de la capture automatique UILabel

0
Michal Mondík