web-dev-qa-db-fra.com

iOS: UILabel multiligne dans la mise en page automatique

Je ne parviens pas à obtenir un comportement de base très simple avec la disposition automatique. Mon contrôleur de vue ressemble à ceci dans IB:

enter image description here

L'étiquette du haut est l'étiquette du titre, je ne sais pas combien de lignes ce sera. J'ai besoin de l'étiquette de titre pour afficher toutes les lignes de texte. J'ai également besoin que les deux autres étiquettes et la petite image soient placées juste en dessous du titre, quelle que soit sa hauteur. J'ai défini des contraintes d'espacement vertical entre les étiquettes et la petite image, ainsi qu'une contrainte d'espacement supérieure entre l'étiquette de titre et son aperçu, ainsi qu'une contrainte d'espacement inférieur entre la petite image et son aperçu. UIView blanc n'a pas de contrainte de hauteur, il devrait donc s'étirer verticalement pour contenir ses sous-vues. J'ai réglé le nombre de lignes pour le titre à 0.

Comment puis-je redimensionner le titre du titre afin qu'il corresponde au nombre de lignes requises par la chaîne? Si j'ai bien compris, je ne peux pas utiliser les méthodes setFrame car j'utilise la disposition automatique. Et je dois utiliser la mise en page automatique car j'ai besoin que ces autres vues restent en dessous de l'étiquette de titre (d'où les contraintes).

Comment puis-je y arriver?

178
James Harpe

Utilisez -setPreferredMaxLayoutWidth sur le UILabel et autolayout devrait gérer le reste.

[label setPreferredMaxLayoutWidth:200.0];

Voir le documentation UILabel sur preferredMaxLayoutWidth .

Mise à jour:

Il suffit de définir la contrainte height dans le storyboard sur Greater than or equal to, il n'est pas nécessaire de définirPreferredMaxLayoutWidth.

249
mwhuss

Développez le nombre de lignes du jeu d'étiquettes sur 0 et, plus important encore, sur la mise en page automatique, réglez la hauteur sur> = x. La mise en page automatique fera le reste. Vous pouvez également contenir vos autres éléments basés sur l’élément précédent afin de les positionner correctement.

auto layout

210
Charlie Wu

Source: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

Taille du contenu intrinsèque d'un texte multiligne

La taille du contenu intrinsèque de UILabel et de NSTextField est ambiguë pour le texte multiligne. La hauteur du texte dépend de la largeur des lignes, ce qui reste à déterminer lors de la résolution des contraintes. Afin de résoudre ce problème, les deux classes ont une nouvelle propriété appelée preferredMaxLayoutWidth, qui spécifie la largeur de ligne maximale pour le calcul de la taille du contenu intrinsèque.

Comme nous ne connaissons généralement pas cette valeur à l’avance, nous devons adopter une approche en deux étapes pour parvenir à ce résultat. Tout d'abord, nous laissons Auto Layout faire son travail, puis nous utilisons le cadre obtenu dans l'étape de présentation pour mettre à jour la largeur maximale préférée et pour réactiver la présentation.

- (void)layoutSubviews
{
    [super layoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [super layoutSubviews];
}

Le premier appel à [super layoutSubviews] est nécessaire pour que l’étiquette puisse obtenir son ensemble de trames, tandis que le second appel est nécessaire pour mettre à jour la présentation après le changement. Si nous omettons le deuxième appel, nous obtenons une erreur NSInternalInconsistencyException, car nous avons apporté des modifications à la passe de présentation qui nécessitent la mise à jour des contraintes, mais nous n'avons pas déclenché de nouveau la présentation.

Nous pouvons également le faire dans une sous-classe d’étiquette:

@implementation MyLabel
- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = self.frame.size.width;
    [super layoutSubviews];
}
@end

Dans ce cas, nous n’avons pas besoin d’appeler d’abord [super layoutSubviews], car lors de l’appel de layoutSubviews, nous avons déjà un cadre sur l’étiquette elle-même.

Pour effectuer cet ajustement à partir du niveau du contrôleur de vue, nous accrochons dans viewDidLayoutSubviews. À ce stade, les cadres de la première passe de mise en page automatique sont déjà définis et nous pouvons les utiliser pour définir la largeur maximale préférée.

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

Enfin, assurez-vous que l’étiquette n’a pas de contrainte de hauteur explicite dont la priorité est supérieure à la priorité de résistance à la compression du contenu de l’étiquette. Sinon, la hauteur calculée du contenu sera dépassée. Assurez-vous de vérifier toutes les contraintes qui peuvent affecter la hauteur de l'étiquette.

44
Anton Matosov

Je me battais juste avec ce scénario exact, mais avec quelques vues supplémentaires qui devaient être redimensionnées et redimensionnées au besoin. Cela me rendait dingue, mais j'ai finalement compris.

Voici la clé: Interface Builder aime introduire des contraintes supplémentaires lorsque vous ajoutez et déplacez des vues et vous ne le remarquerez peut-être pas. Dans mon cas, j'avais une vue à mi-chemin avec une contrainte supplémentaire qui spécifiait la taille entre elle et son aperçu, en la fixant à ce point. Cela signifiait que rien au-dessus ne pourrait redimensionner plus grand car cela irait à l'encontre de cette contrainte.

Un moyen facile de savoir si tel est le cas est d’essayer de redimensionner l’étiquette manuellement. Est-ce que IB vous laisse la cultiver? Si tel est le cas, les étiquettes ci-dessous se déplacent-elles comme prévu? Avant de redimensionner, assurez-vous de cocher ces deux options pour voir comment vos contraintes déplaceront vos vues:

IB Menu

Si la vue est bloquée, suivez les vues qui se trouvent en dessous et assurez-vous que l'une d'entre elles ne dispose pas d'un espace supérieur pour la contrainte de super vue. Ensuite, assurez-vous que votre option de nombre de lignes pour l'étiquette est définie sur 0 et qu'elle devrait s'occuper du reste.

16
Cory Imdieke

Je trouve que vous avez besoin des éléments suivants:

  • Une contrainte supérieure
  • Une contrainte dominante (par exemple du côté gauche)
  • Une contrainte de fin (par exemple à droite)
  • Définissez la priorité de calage du contenu, horizontal sur bas, afin de remplir l'espace donné si le texte est court.
  • Définissez la résistance de compression du contenu, horizontale à faible, pour que le contenu soit enveloppé au lieu d'essayer de devenir plus large.
  • Définissez le nombre de lignes sur 0.
  • Définissez le mode de saut de ligne sur Retour à la ligne.
5
Chris

Aucune des solutions différentes trouvées dans les nombreuses rubriques sur le sujet ne fonctionnait parfaitement pour mon cas (x étiquettes multilignes dynamiques dans les cellules de la vue tableau dynamique).

J'ai trouvé un moyen de le faire:

Après avoir défini les contraintes sur votre étiquette et défini sa propriété multiligne à 0, créez une sous-classe de UILabel; J'ai appelé le mien AutoLayoutLabel:

@implementation AutoLayoutLabel

- (void)layoutSubviews{
    [self setNeedsUpdateConstraints];
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}

@end
0
Tanguy G.

J'ai un UITableViewCell qui a une étiquette d'habillage de texte. J'ai travaillé le texte comme suit.

1) Définissez les contraintes UILabel comme suit.

enter image description here

2) Set no. de lignes à 0.

3) Ajout de la contrainte de hauteur UILabel à UITableViewCell.

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) Sur UITableViewCell:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5
0
A.G