152 votes

UILabel sizeToFit ne fonctionne pas avec autolayout ios6

Comment suis-je censé configurer par programme (et dans quelle méthode) une UILabel dont la hauteur dépend de son texte ? J'ai essayé de le configurer en utilisant une combinaison de Storyboard et de code, mais en vain. Tout le monde recommande sizeToFit pendant le réglage lineBreakMode y numberOfLines . Cependant, peu importe si je mets ce code dans viewDidLoad: , viewDidAppear: ou viewDidLayoutSubviews Je n'arrive pas à le faire fonctionner. Soit je fais en sorte que la boîte soit trop petite pour un texte long et elle ne s'agrandit pas, soit je la fais trop grande et elle ne rétrécit pas.

405voto

Mark Kryzhanouski Points 4165

Veuillez noter que dans la plupart des cas La solution de Matt fonctionne comme prévu. Mais si cela ne fonctionne pas pour vous, lisez ce qui suit.

Pour que votre étiquette redimensionne automatiquement sa hauteur, vous devez procéder comme suit :

  1. Définir les contraintes de mise en page pour l'étiquette
  2. Définir la contrainte de hauteur avec une faible priorité. Elle doit être inférieure à ContentCompressionResistancePriority.
  3. Set numberOfLines = 0
  4. Définir ContentHuggingPriority plus haut que la priorité de hauteur de l'étiquette
  5. Définit la preferredMaxLayoutWidth pour l'étiquette. Cette valeur est utilisée par l'étiquette pour calculer sa hauteur.

Par exemple :

self.descriptionLabel = [[UILabel alloc] init];
self.descriptionLabel.numberOfLines = 0;
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.preferredMaxLayoutWidth = 200;

[self.descriptionLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.descriptionLabel];

NSArray* constrs = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[descriptionLabel_]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)];
[self addConstraints:constrs];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[descriptionLabel_]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
[self.descriptionLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[descriptionLabel_(220@300)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];

Utilisation de l'Interface Builder

  1. Définissez quatre contraintes. La contrainte de hauteur est obligatoire. enter image description here

  2. Ensuite, allez dans l'inspecteur des attributs de l'étiquette et définissez le nombre de lignes à 0. enter image description here

  3. Allez dans l'inspecteur de taille de l'étiquette et augmentez la priorité verticale ContentHuggingPriority et la priorité verticale ContentCompressionResistancePriority.
    enter image description here

  4. Sélectionnez et modifiez la contrainte de hauteur.
    enter image description here

  5. Et diminuer la priorité de la contrainte de hauteur.
    enter image description here

Profitez-en. :)

65voto

matt Points 60113

Dans iOS 6, en utilisant autolayout, si les côtés (ou la largeur) et le haut d'une étiquette UILabel sont épinglés, elle automatiquement s'agrandit et se rétrécit verticalement pour s'adapter à son contenu. pas de code du tout et pas besoin de jouer avec sa résistance à la compression ou autre. C'est très simple.

Dans des cas plus complexes, il suffit de définir l'option preferredMaxLayoutWidth .

Dans tous les cas, la bonne chose se produit automatiquement.

42voto

Max MacLeod Points 8425

Bien que la question porte sur la programmation, ayant rencontré le même problème, et préférant travailler dans Interface Builder, j'ai pensé qu'il pourrait être utile d'ajouter aux réponses existantes une solution d'Interface Builder.

La première chose est d'oublier sizeToFit . La mise en page automatique s'en chargera pour vous en fonction de la taille intrinsèque du contenu.

Le problème est donc le suivant : comment faire pour qu'une étiquette s'adapte à son contenu avec la mise en page automatique ? Plus précisément - car la question le mentionne - la hauteur. Notez que les mêmes principes s'appliquent à la largeur.

Commençons donc par un exemple d'UILabel dont la hauteur est fixée à 41px :

enter image description here

Comme vous pouvez le voir dans la capture d'écran ci-dessus, "This is my text" a un remplissage au-dessus et au-dessous. Il s'agit du remplissage entre la hauteur de l'UILabel et son contenu, le texte.

Si nous exécutons l'application dans le simulateur, nous constatons la même chose :

enter image description here

Maintenant, sélectionnons l'étiquette UILabel dans Interface Builder et examinons les paramètres par défaut dans l'inspecteur de taille :

enter image description here

Notez la contrainte mise en évidence ci-dessus. Il s'agit de la Priorité au contenu . Comme le décrit Erica Sadun dans l'excellent ouvrage intitulé La mise en page automatique d'iOS démystifiée c'est :

la façon dont une vue préfère éviter un rembourrage supplémentaire autour de son contenu principal

Pour nous, avec l'UILabel, le contenu principal est le texte.

Nous arrivons ici au cœur de ce scénario de base. Nous avons donné deux contraintes à notre étiquette de texte. Elles sont en conflit. La première dit "la hauteur doit être égale à 41 pixels" . L'autre dit "étreindre la vue jusqu'au bout pour qu'il n'y ait pas de rembourrage supplémentaire". . Dans notre cas, le câlin de la vue à son texte donc nous n'avons pas de rembourrage supplémentaire.

Maintenant, avec la mise en page automatique, avec deux instructions différentes qui disent de faire des choses différentes, le runtime doit choisir l'une ou l'autre. Il ne peut pas faire les deux. L'UILabel ne peut pas avoir une hauteur de 41 pixels, y n'ont pas de rembourrage.

La façon de résoudre ce problème est de spécifier la priorité. Une instruction doit avoir une priorité plus élevée que l'autre. Si les deux instructions disent des choses différentes, et ont la même priorité, une exception se produira.

Alors essayons. Ma contrainte de hauteur a une priorité de 1000 qui est requis . La hauteur d'étreinte du contenu est 250 qui est faible . Que se passe-t-il si nous réduisons la priorité de la contrainte de hauteur à 249 ?

enter image description here

Maintenant, nous pouvons voir que la magie commence à opérer. Essayons dans la simulation :

enter image description here

Génial ! L'étreinte du contenu est atteinte. Seulement parce que la priorité de la hauteur 249 est moins que la priorité d'embrasser le contenu 250 . En gros, je dis "la hauteur que je spécifie ici est moins importante que ce que j'ai spécifié pour l'étreinte du contenu" . Donc, l'étreinte du contenu gagne.

En résumé, pour que l'étiquette s'adapte au texte, il suffit de spécifier la contrainte de hauteur - ou de largeur - et de définir correctement cette priorité en association avec la contrainte de priorité d'adaptation du contenu de cet axe.

Je laisse l'équivalent pour la largeur comme un exercice pour le lecteur !

7voto

Nick Wood Points 260

J'ai remarqué que dans IOS7, sizeToFit ne fonctionnait pas non plus - peut-être que la solution peut vous aider aussi.

[#UITEXTVIEW# sizeToFit] ; [#UITEXTVIEW# layoutIfNeed] ;

3voto

Adam Block Points 328

Dans mon cas, je créais une sous-classe UIView qui contenait une UILabel (de longueur inconnue). Dans iOS7, le code était simple : définir les contraintes, ne pas se soucier de l'étreinte du contenu ou de la résistance à la compression, et tout fonctionnait comme prévu.

Mais dans iOS6, l'UILabel était toujours réduit à une seule ligne. Aucune des réponses ci-dessus n'a fonctionné pour moi. Les paramètres d'adaptation du contenu et de résistance à la compression étaient ignorés. La seule solution permettant d'éviter le découpage consistait à inclure une largeur maximale préférée (preferredMaxLayoutWidth) dans l'étiquette. Mais je ne savais pas à quoi fixer la largeur préférée, car la taille de sa vue parente était inconnue (en fait, elle serait définie par le contenu).

J'ai enfin trouvé la solution aquí . Comme je travaillais sur une vue personnalisée, je pouvais simplement ajouter la méthode suivante pour définir la largeur de disposition préférée après que les contraintes aient été calculées une fois, puis les recalculer :

- (void)layoutSubviews
{
    // Autolayout hack required for iOS6
    [super layoutSubviews];
    self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
    [super layoutSubviews];
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X