ios guidelines - AutoLayout avec des UIViews cachés?




6 Answers

Ma préférence personnelle pour afficher / masquer des vues est de créer un IBOutlet avec la contrainte de largeur ou de hauteur appropriée.

Ensuite, je mets à jour la valeur constant à 0 pour masquer, ou quelle que soit la valeur à afficher.

Le gros avantage de cette technique est que les contraintes relatives seront maintenues. Par exemple, disons que vous avez vue A et visualisez B avec un écart horizontal de x . Lorsque la vue Une constant largeur est définie sur 0.f vue B se déplace vers la gauche pour remplir cet espace.

Il n'est pas nécessaire d'ajouter ou de supprimer des contraintes, ce qui est une opération lourde. La simple mise à jour de la constant la contrainte fera l'affaire.

pdf design

J'ai l'impression que c'est un paradigme assez courant pour montrer / cacher des UIViews , le plus souvent des UILabels , en fonction de la logique métier. Ma question est, 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 de liste dynamique de 1-3 fonctionnalités.

En ce moment j'ai un espace supérieur de 10px du bouton à la dernière étiquette, qui évidemment ne glissera pas vers le haut quand l'étiquette est cachée. En ce moment j'ai créé un débouché à cette contrainte et j'ai modifié la constante en fonction du nombre d'étiquettes affichées. C'est évidemment un peu hacky car j'utilise des valeurs constantes négatives pour pousser le bouton sur les cadres cachés. C'est aussi mauvais parce qu'il n'est pas contraint à des éléments de mise en page réels, juste des calculs statiques basés sur des hauteurs / rembourrages connus d'autres éléments, et de toute évidence luttant contre ce que l'AutoLayout a été construit.

Je pourrais évidemment créer de nouvelles contraintes en fonction de mes étiquettes dynamiques, mais c'est beaucoup de microgestion et beaucoup de verbosité pour essayer de simplement réduire certains espaces. Y a-t-il de meilleures approches? Changer la taille de l'image 0,0 et laisser AutoLayout faire son truc sans manipulation de contraintes? Suppression des vues complètement?

Honnêtement, il suffit de modifier la constante du contexte de la vue cachée pour obtenir 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




UIStackView est probablement le chemin à parcourir pour iOS 9+. Non seulement il gère la vue cachée, mais il supprime également l'espacement et les marges supplémentaires s'il est correctement configuré.




Sous-classer la vue et remplacer la func intrinsicContentSize() -> CGSize . CGSizeZero juste CGSizeZero si la vue est cachée.







La meilleure pratique consiste à ajouter une hauteur ou une contrainte une fois que toutes les contraintes de disposition sont correctes, selon la manière dont vous souhaitez que les vues environnantes se déplacent et connectent la contrainte dans une propriété IBOutlet .

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

dans le code yo suffit de mettre la constante à 0 et de l' activer , de masquer le contenu, ou de le désactiver pour afficher le contenu. C'est mieux que de jouer avec la valeur constante d'une sauvegarde-restauration. N'oubliez pas d'appeler layoutIfNeeded après.

Si le contenu à masquer est groupé, la meilleure pratique consiste à placer tout le contenu 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 configuré votre configuration, vous pouvez la tester dans IntefaceBuilder en définissant votre contrainte sur 0, puis revenir à la valeur d'origine. N'oubliez pas de vérifier les autres priorités de contraintes afin de ne pas avoir de conflit du tout. Une autre façon de le tester est de le mettre à 0 et de mettre la priorité à 0, mais vous ne devez pas oublier de le restaurer à la plus haute priorité.




Je fournirai aussi ma solution, pour offrir de la variété.) Je pense que créer un point de vente pour la largeur / hauteur de chaque article et pour l'espacement est ridicule et gonfle le code, les erreurs possibles et le nombre de complications.

Ma méthode supprime toutes les vues (dans mon cas, les instances UIImageView), sélectionne celles qui ont besoin d'être rajoutées, et dans une boucle, elle rajoute chacune et crée de nouvelles contraintes. C'est vraiment très simple, veuillez suivre. Voici mon code rapide et sale pour le faire:

// remove all views
[self.twitterImageView removeFromSuperview];
[self.localQuestionImageView removeFromSuperview];

// self.recipients always has to be present
NSMutableArray *items;
items = [@[self.recipients] mutableCopy];

// optionally add the twitter image
if (self.question.sharedOnTwitter.boolValue) {
    [items addObject:self.twitterImageView];
}

// optionally add the location image
if (self.question.isLocal) {
    [items addObject:self.localQuestionImageView];
}

UIView *previousItem;
UIView *currentItem;

previousItem = items[0];
[self.contentView addSubview:previousItem];

// now loop through, add the items and the constraints
for (int i = 1; i < items.count; i++) {
    previousItem = items[i - 1];
    currentItem = items[i];

    [self.contentView addSubview:currentItem];

    [currentItem mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(previousItem.mas_centerY);
        make.right.equalTo(previousItem.mas_left).offset(-5);
    }];
}


// here I just connect the left-most UILabel to the last UIView in the list, whichever that was
previousItem = items.lastObject;

[self.userName mas_remakeConstraints:^(MASConstraintMaker *make) {
    make.right.equalTo(previousItem.mas_left);
    make.leading.equalTo(self.text.mas_leading);
    make.centerY.equalTo(self.attachmentIndicator.mas_centerY);;
}];

Je reçois une mise en page et un espacement propres et cohérents. Mon code utilise la maçonnerie, je le recommande fortement: https://github.com/SnapKit/Masonry




Related

ios objective-c autolayout