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?
La bonne réponse est ici: https://stackoverflow.com/a/43110590/566360
UILabel
dans une UIView
(Éditeur -> Incorporer dans -> Afficher) 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.
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.
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é: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.
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
UIStackView
verticale composée de UILabel
s 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)
// 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])
}
}
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.
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.
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.
Définir preferredMaxLayoutWidth sur UILabel a fonctionné pour moi
self.myLabel.preferredMaxLayoutWidth = self.bounds.size.width;
C'est presque comme @ Andy's Answer, mais vous pouvez ajouter votre UILabel
en extra UIStackview
, la verticale a fonctionné pour moi.
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.
Ce qui a fonctionné pour moi!
stackview: alignement: remplissage, distribution: remplissage, contrainte largeur proportionnelle à superview ex. 0,8
étiquette: centre et lignes = 0
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)
}
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 .
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.
Pour quiconque ne peut toujours pas le faire fonctionner. Essayez de définir Autoshrink avec une échelle de police minimale sur ce UILabel.