167 votes

AutoLayout avec UIViews cachés ?

J'ai l'impression que c'est un paradigme assez commun de montrer/cacher UIViews le plus souvent UILabels en fonction de la logique commerciale. Ma question est la suivante : quelle est la meilleure façon d'utiliser AutoLayout pour répondre aux vues cachées comme si leur cadre était 0x0. Voici un exemple d'une liste dynamique de 1 à 3 fonctionnalités.

Dynamic features list

Actuellement, il y a un espace de 10px entre le bouton et la dernière étiquette, qui ne peut évidemment pas glisser vers le haut lorsque l'étiquette est cachée. Pour l'instant, j'ai créé une sortie pour cette contrainte et je modifie la constante en fonction du nombre d'étiquettes que j'affiche. C'est évidemment un peu compliqué puisque j'utilise des valeurs constantes négatives pour faire glisser le bouton vers le haut au-dessus des cadres cachés. C'est également mauvais parce que la contrainte n'est pas liée à des éléments de mise en page réels, mais à des calculs statiques sournois basés sur des hauteurs/plages connues d'autres éléments, et que cela va à l'encontre de ce pour quoi AutoLayout a été conçu.

Je pourrais évidemment créer de nouvelles contraintes en fonction de mes étiquettes dynamiques, mais c'est beaucoup de microgestion et de verbosité pour essayer de réduire simplement quelques espaces blancs. Existe-t-il de meilleures approches ? Changer la taille du cadre 0,0 et laisser AutoLayout faire son travail sans manipuler les contraintes ? Supprimer complètement les vues ?

Honnêtement, la modification de la constante dans le contexte de la vue cachée ne nécessite qu'une seule ligne de code avec un calcul simple. Recréer de nouvelles contraintes avec constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant: semble si lourd.

Edit Feb 2018 : Voir la réponse de Ben avec UIStackView s

0 votes

Merci Ryan pour cette question. Je devenais fou de savoir comment faire dans les cas que vous avez demandés. Chaque fois que je cherche le tutoriel pour autolayout, la plupart d'entre eux disent de se référer au site de tutoriel raywenderlich que je trouve un peu difficile à comprendre.

5voto

Daniel Points 327

Sous-classez la vue et surchargez func intrinsicContentSize() -> CGSize . Retournez simplement CGSizeZero si la vue est cachée.

5voto

Matt Koala Points 2081

Je viens de découvrir que pour qu'un UILabel ne prenne pas de place, il faut le cacher ET donner à son texte la valeur d'une chaîne vide. (iOS 9)

Le fait de connaître ce fait/bogue pourrait aider certaines personnes à simplifier leurs mises en page, peut-être même celle de la question initiale, alors je me suis dit que j'allais le poster.

4voto

Albert Bori Points 596

Je suis surpris qu'il n'y ait pas une approche plus élégante fournie par UIKit pour ce comportement souhaité. Il semble que ce soit une chose très commune que de vouloir être capable de faire.

Puisque la connexion des contraintes à IBOutlets et en fixant leurs constantes à 0 était dégoûtant (et a causé NSLayoutConstraint lorsque votre vue avait des sous-vues), j'ai décidé de créer une extension qui donne une une approche simple et dynamique pour cacher/afficher une UIView qui a des contraintes de mise en page automatique

Il ne fait que masquer la vue et supprimer les contraintes extérieures. Lorsque vous réaffichez la vue, elle réintroduit les contraintes. Le seul problème est que vous devrez spécifier des contraintes de basculement flexibles pour les vues environnantes.

Modifier Cette réponse s'adresse aux versions iOS 8.4 et inférieures. Dans iOS 9, il suffit d'utiliser l'option UIStackView approche.

4voto

Jorge Arimany Points 11

La meilleure pratique consiste, une fois que toutes les contraintes de mise en page sont correctes, à ajouter une contrainte de hauteur ou de avec, en fonction de la façon dont vous souhaitez que les vues environnantes se déplacent, et à connecter la contrainte dans un fichier de type IBOutlet propriété.

Assurez-vous que vos propriétés sont strong

dans le code, il suffit de mettre la constante à 0 et activer pour en cacher le contenu, ou désactiver pour afficher le contenu. C'est mieux que de s'embrouiller avec la valeur constante et de la sauvegarder-restaurer. N'oubliez pas d'appeler layoutIfNeeded après.

Si le contenu à masquer est groupé, la meilleure pratique consiste à le placer dans une vue et à ajouter les contraintes à cette vue.

@property (strong, nonatomic) IBOutlet UIView *myContainer;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *myContainerHeight; //should be strong!!

-(void) showContainer
{
    self.myContainerHeight.active = NO;
    self.myContainer.hidden = NO;
    [self.view layoutIfNeeded];
}
-(void) hideContainer
{
    self.myContainerHeight.active = YES;
    self.myContainerHeight.constant = 0.0f;
    self.myContainer.hidden = YES;
    [self.view layoutIfNeeded];
}

Une fois que vous avez votre configuration, vous pouvez la tester dans IntefaceBuilder en mettant votre contrainte à 0, puis en la remettant à sa valeur initiale. N'oubliez pas de vérifier les priorités des autres contraintes afin qu'il n'y ait aucun conflit lorsqu'elles sont cachées. Une autre façon de la tester est de la mettre à 0 et de fixer la priorité à 0, mais il ne faut pas oublier de la rétablir à la priorité la plus élevée.

3voto

Damien Points 468

Je construis une catégorie pour mettre à jour les contraintes facilement :

[myView1 hideByHeight:YES];

Répondez ici : Hide autolayout UIView : Comment obtenir une NSLayoutConstraint existante pour mettre à jour cette dernière ?

enter image description here

8 votes

Malheureusement, vous obtenez un double espacement à cet endroit, juste là où la flèche jaune pointe.

0 votes

Comme pour les autres solutions ci-dessus, je pense. Pas idéal du tout.

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