Comment utiliser la mise en page automatique pour déplacer d'autres vues lorsqu'une vue est masquée?


334

J'ai conçu ma cellule personnalisée dans IB, je l'ai sous-classée et j'ai connecté mes prises à ma classe personnalisée. J'ai trois sous-vues dans le contenu des cellules qui sont: UIView (cdView) et deux étiquettes (titleLabel et emailLabel). En fonction des données disponibles pour chaque ligne, je souhaite parfois avoir UIView et deux étiquettes affichées dans ma cellule et parfois seulement deux étiquettes. Ce que j'essaie de faire, c'est de définir des contraintes de cette façon si je définis la propriété UIView sur caché ou que je la supprime de la vue d'ensemble, les deux étiquettes se déplaceront vers la gauche. J'ai essayé de définir la contrainte de tête UIView sur Superview (contenu de cellule) pour 10px et les contraintes de tête UILabels pour 10 px sur la vue suivante (UIView). Plus tard dans mon code

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(IndexPath *)indexPath {
...
Record *record = [self.records objectAtIndex:indexPath.row];

if ([record.imageURL is equalToString:@""]) {
     cell.cdView.hidden = YES;
}

Je cache mon cell.cdView et j'aimerais que les étiquettes se déplacent vers la gauche mais elles restent dans la même position dans Cell. J'ai essayé de supprimer cell.cdView de superview mais cela n'a pas fonctionné non plus. J'ai joint une image pour clarifier ce que je suis.

cellule

Je sais comment procéder par programme et je ne cherche pas cette solution. Ce que je veux, c'est définir des contraintes dans IB et je m'attends à ce que mes sous-vues se déplacent dynamiquement si d'autres vues sont supprimées ou masquées. Est-il possible de le faire dans IB avec la mise en page automatique?

.....

Changer la valeur d'exécution des contraintes - vérifiez cette réponse
Kampai

Pour ce cas spécifique, vous pouvez également utiliser un UIStackView. lorsque vous cachez le cd, les labels occuperont leur espace
Marco Pappalardo

Réponses:


373

C'est possible, mais vous devrez faire un peu de travail supplémentaire. Il y a quelques éléments conceptuels à éviter en premier:

  • Les vues masquées, même si elles ne dessinent pas, participent toujours à la mise en page automatique et conservent généralement leurs images , laissant les autres vues associées à leur place.
  • Lors de la suppression d'une vue de sa vue d' ensemble , toutes les contraintes associées sont également supprimées de cette hiérarchie de vues.

Dans votre cas, cela signifie probablement:

  • Si vous définissez votre vue de gauche pour qu'elle soit masquée, les étiquettes restent en place, car cette vue de gauche prend toujours de la place (même si elle n'est pas visible).
  • Si vous supprimez votre vue de gauche, vos étiquettes seront probablement laissées de manière ambiguë, car vous n'avez plus de contraintes pour les bords gauches de vos étiquettes.

Ce que vous devez faire, c'est judicieusement surcharger vos étiquettes. Laissez vos contraintes existantes (espace de 10 pts à l'autre vue), mais ajoutez une autre contrainte: éloignez les bords gauches de vos étiquettes de 10 pts du bord gauche de leur vue d'ensemble avec une priorité non requise (la priorité élevée par défaut fonctionnera probablement bien).

Ensuite, lorsque vous souhaitez qu'ils se déplacent vers la gauche, supprimez complètement la vue de gauche. La contrainte obligatoire de 10 points sur la vue de gauche disparaîtra avec la vue à laquelle elle se rapporte, et il ne vous restera qu'une contrainte de haute priorité pour que les étiquettes soient à 10 pts de leur vue d'ensemble. Lors de la prochaine passe de mise en page, cela devrait les faire s'étendre vers la gauche jusqu'à ce qu'ils remplissent la largeur de la vue d'ensemble, mais pour votre espacement autour des bords.

Une mise en garde importante: si jamais vous voulez que votre vue de gauche revienne dans l'image, non seulement vous devez l'ajouter à nouveau dans la hiérarchie des vues, mais vous devez également rétablir toutes ses contraintes en même temps. Cela signifie que vous avez besoin d'un moyen de remettre votre contrainte d'espacement de 10 points entre la vue et ses étiquettes chaque fois que cette vue s'affiche à nouveau.


8
Bien que cette réponse fonctionnera certainement, l'OMI, la contrainte excessive de gérer divers cas d'utilisation semble être une odeur de code - d'autant plus que vous devrez rétablir toutes les contraintes pour toutes les vues supprimées que vous souhaitez afficher à nouveau.
memmons

À mon avis, ce n'est pas la voie à suivre. Vous devez plutôt utiliser une contrainte largeur / hauteur pour la vue que vous souhaitez masquer.
ullstrm

26
Je suis respectueusement en désaccord. Si vous (par exemple) définissez la largeur de la vue sur 0, vous rencontrerez deux problèmes. Tout d'abord, vous avez maintenant un double espacement entre la vue d'ensemble et la vue visible: |-(space)-[hidden(0)]-(space)-[visible]c'est effectivement |-(2*space)-[visible]. Deuxièmement, cette vue peut commencer à générer des violations de contraintes en fonction de son propre sous-arbre de vue et de ses propres contraintes - vous ne pouvez pas garantir que vous pouvez contraindre arbitrairement une vue à une largeur de 0 et la faire fonctionner.
Tim

1
Si vous utilisez une vue avec une taille de contenu intrinsèque, la réponse de Tim semble être la solution unique.
balkoth

Merci Tim. J'ai défini une contrainte de 0 avec une priorité plus élevée pour éviter les incompatibilités de contraintes, mais maintenant je me rends compte qu'il y a un problème avec le double espacement. Je n'ai pas eu ce problème parce que je ne montre jamais les deux vues ensemble (mon cas:) |-[otherViews]-[eitherThis][orThis]-|, mais je me suis finalement heurté à ce problème.
Ferran Maylinch du

207

L'ajout ou la suppression de contraintes pendant l'exécution est une opération lourde qui peut affecter les performances. Cependant, il existe une alternative plus simple.

Pour la vue que vous souhaitez masquer, définissez une contrainte de largeur. Contraignez les autres vues avec un écart horizontal de tête à cette vue.

Pour masquer, mettez à jour la .constantcontrainte de largeur à 0.f. Les autres vues se déplaceront automatiquement vers la gauche pour prendre position.

Voir mon autre réponse ici pour plus de détails:

Comment changer les contraintes d'étiquette pendant l'exécution?


29
Le seul problème avec cette solution est que la marge à gauche sera le double de ce que vous voulez probablement, donc je mettrais à jour l'une de ces contraintes aussi, mais même là, je pense que c'est moins de travail que de supprimer la sous-vue.
José Manuel Sánchez

2
@ skinsfan00atg Si vous utilisez une vue avec une taille de contenu intrinsèque, vous ne pouvez pas utiliser cette solution.
balkoth

@balkoth pourquoi pas? Vous pouvez simplement réduire la priorité du contenu
Max MacLeod

2
@MaxMacLeod Si vous réduisez la priorité d'ajustement de contenu, vous n'utilisez pas la taille de contenu intrinsèque, vous utilisez la taille indiquée par la contrainte.
balkoth

2
@MaxMacLeod Ok, j'ai compris ce que tu veux dire. Vous devez définir la priorité de la résistance à la compression sur 0 (et non l'étirement du contenu) dans le code lorsque vous souhaitez masquer la vue et lorsque vous souhaitez afficher à nouveau restaurer cette valeur. En dehors de cela, vous devez ajouter une contrainte dans le générateur d'interface pour définir la taille de la vue à 0. Il n'est pas nécessaire de toucher cette contraint dans le code.
balkoth

87

Pour ceux qui prennent en charge iOS 8+ uniquement, une nouvelle propriété booléenne est active . Cela aidera à activer dynamiquement uniquement les contraintes nécessaires

La sortie de contrainte PS doit être forte , pas faible

Exemple:

@IBOutlet weak var optionalView: UIView!
@IBOutlet var viewIsVisibleConstraint: NSLayoutConstraint!
@IBOutlet var viewIsHiddenConstraint: NSLayoutConstraint!

func showView() {
    optionalView.isHidden = false
    viewIsVisibleConstraint.isActive = true
    viewIsHiddenConstraint.isActive = false
}

func hideView() {
    optionalView.isHidden = true
    viewIsVisibleConstraint.isActive = false
    viewIsHiddenConstraint.isActive = true
}

Pour corriger une erreur dans le storyboard, vous devrez également décocher la Installedcase pour l'une de ces contraintes.

UIStackView (iOS 9+)
Une autre option consiste à encapsuler vos vues UIStackView. Une fois la vue masquée UIStackView, la mise à jour sera mise à jour automatiquement


actif fonctionne en partie. Mais si je l'utilise dans une cellule réutilisable, d'activer à désactiver, ça marche, mais pas à désactiver pour activer. Des idées? Ou pourriez-vous donner un exemple peut-être?
Aoke Li

10
Cela se produit car la contrainte désactivée n'est pas chargée ou désallouée. Votre sortie de contrainte doit être forte, pas faible
Silmaril

Où peut-on trouver cette propriété "active"?
Lakshmi Reddy


Il semble que l'activité de contrainte excessive + ensemble de contraintes puisse être la réponse la plus raisonnable.
Ting Yi Shih

68

UIStackViewrepositionne automatiquement ses vues lorsque la hiddenpropriété est modifiée sur l'une de ses sous-vues (iOS 9+).

UIView.animateWithDuration(1.0) { () -> Void in
   self.mySubview.hidden = !self.mySubview.hidden
}

Aller à 11:48 dans cette vidéo WWDC pour une démo:

Mystères de la mise en page automatique, partie 1


J'ai caché une vue de pile imbriquée et toute la vue de pile contenant a disparu.
Ian Warburton

5
Ce devrait être la réponse acceptée. Suivre les recommandations Apple de la WWWC 2015 sur la conception du générateur d'interface.
thibaut noah

@thibautnoah Et qu'en est-il du support iOS 8?
bagage

5
@bagage Sauf si vous êtes facebook ou google, vous pouvez le supprimer. Avec une couverture au-delà d'iOS 9, vous prendrez en charge plus de 90% des appareils, plus que suffisant. La prise en charge ci-dessous paralysera votre processus de développement et vous empêchera d'utiliser les dernières fonctionnalités imo
thibaut noah

16

Mon projet utilise une @IBDesignablesous-classe personnalisée de UILabel(pour assurer la cohérence de la couleur, de la police, des encarts, etc.) et j'ai mis en œuvre quelque chose comme ceci:

override func intrinsicContentSize() -> CGSize {
    if hidden {
        return CGSizeZero
    } else {
        return super.intrinsicContentSize()
    }
}

Cela permet à la sous-classe d'étiquettes de participer à la mise en page automatique, mais ne prend pas d'espace lorsqu'elle est masquée.


13

Pour les Googlers: en s'appuyant sur la réponse de Max, pour résoudre le problème de rembourrage que beaucoup ont remarqué, j'ai simplement augmenté la hauteur de l'étiquette et utilisé cette hauteur comme séparateur au lieu du rembourrage réel. Cette idée pourrait être développée pour tout scénario contenant des vues.

Voici un exemple simple:

Capture d'écran IB

Dans ce cas, je mappe la hauteur du libellé Auteur à un niveau approprié IBOutlet:

@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;

et lorsque je règle la hauteur de la contrainte sur 0.0f, nous conservons le "rembourrage", car la hauteur du bouton Lecture le permet.


Pour ceux qui sont nouveaux, NSLayoutConstraintje crois que vous souhaitez mettre à jour la constantpropriété de votre authorLabelHeight.
Kyle

8

connectez la contrainte entre uiview et les étiquettes en tant qu'IBOutlet et définissez le membre prioritaire sur une valeur inférieure lorsqu'il est masqué = YES


3
Vous ne pouvez pas ajuster la priorité d'une NSLayoutConstraint une fois qu'elle est établie; vous devez supprimer et lire une nouvelle contrainte avec une priorité différente.
Tim

7
J'ai réussi à faire fonctionner cette méthode. J'ai un cas qui utilise une étiquette et un bouton, où j'ai besoin de cacher le bouton et de développer l'étiquette. J'ai deux contraintes, l'une initialement avec la priorité 751 et l'autre avec 750. Puis quand je cache le bouton, je retourne les priorités et la longueur de l'étiquette augmente. Il convient de noter que si vous essayez de faire passer la priorité supérieure à 1000, vous obtenez une erreur "La mutation d'une priorité de requise à non sur une contrainte installée (ou vice-versa) n'est pas prise en charge.". Alors ne le faites pas et vous semblez aller bien. Xcode 5.1 / viewDidLoad.
John Bushnell

8

J'ai fini par créer 2 xibs. Un avec la vue de gauche et un sans. J'ai enregistré les deux dans le contrôleur, puis j'ai décidé lequel utiliser pendant cellForRowAtIndexPath.

Ils utilisent la même classe UITableViewCell. L'inconvénient est qu'il y a une certaine duplication du contenu entre les xibs, mais ces cellules sont assez basiques. L'avantage est que je n'ai pas beaucoup de code pour gérer manuellement la suppression de la vue, la mise à jour des contraintes, etc.

En général, c'est probablement une meilleure solution car ce sont des dispositions techniquement différentes et devraient donc avoir des xibs différents.

[self.table registerNib:[UINib nibWithNibName:@"TrackCell" bundle:nil] forCellReuseIdentifier:@"TrackCell"];
[self.table registerNib:[UINib nibWithNibName:@"TrackCellNoImage" bundle:nil] forCellReuseIdentifier:@"TrackCellNoImage"];

TrackCell *cell = [tableView dequeueReusableCellWithIdentifier:(appDelegate.showImages ? @"TrackCell" : @"TrackCellNoImage") forIndexPath:indexPath];

7

Dans ce cas, je mappe la hauteur du libellé Auteur à un IBOutlet approprié:

@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;

et quand je règle la hauteur de la contrainte à 0.0f, nous conservons le "padding", car la hauteur du bouton Play le permet.

cell.authorLabelHeight.constant = 0;

entrez la description de l'image ici entrez la description de l'image ici


6

Utilisez deux UIStackView Horizontal et Vertical, quand une vue de sous-vue dans la pile est masquée, d'autres sous-vues de pile seront déplacées, utilisez Distribution -> Remplir proportionnellement pour la pile verticale avec deux UILabels et devez définir des contraintes de largeur et de hauteur pour la première UIViewentrez la description de l'image ici


2

Essayez ceci, j'ai implémenté le code ci-dessous,

J'ai une vue sur ViewController dans laquelle trois autres vues ont été ajoutées. Lorsqu'une vue est masquée, deux autres vues se déplacent, suivez les étapes ci-dessous. ,

Fichier 1.ViewController.h

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIView *viewOne;
@property (strong, nonatomic) IBOutlet UIView *viewTwo;
@property (strong, nonatomic) IBOutlet UIView *viewThree;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewOneWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewTwoWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewThreeWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewBottomWidth;
@end

2.ViewController.m

 #import "ViewController.h"
 @interface ViewController ()
{
  CGFloat viewOneWidthConstant;
  CGFloat viewTwoWidthConstant;
  CGFloat viewThreeWidthConstant;
  CGFloat viewBottomWidthConstant;
}
@end

@implementation ViewController
@synthesize viewOne, viewTwo, viewThree;

- (void)viewDidLoad {
  [super viewDidLoad];
 // Do any additional setup after loading the view, typically from a 
  nib.

  /*
   0  0   0
   0  0   1
   0  1   0
   0  1   1
   1  0   0
   1  0   1
   1  1   0
   1  1   1
   */

  //    [viewOne setHidden:NO];
  //    [viewTwo setHidden:NO];
  //    [viewThree setHidden:NO];

  //    [viewOne setHidden:NO];
  //    [viewTwo setHidden:NO];
  //    [viewThree setHidden:YES];

  //    [viewOne setHidden:NO];
  //    [viewTwo setHidden:YES];
  //    [viewThree setHidden:NO];

  //    [viewOne setHidden:NO];
  //    [viewTwo setHidden:YES];
  //    [viewThree setHidden:YES];


  //    [viewOne setHidden:YES];
  //    [viewTwo setHidden:NO];
  //    [viewThree setHidden:NO];

  //    [viewOne setHidden:YES];
  //    [viewTwo setHidden:NO];
  //    [viewThree setHidden:YES];

 //    [viewOne setHidden:YES];
 //    [viewTwo setHidden:YES];
 //    [viewThree setHidden:NO];

//    [viewOne setHidden:YES];
//    [viewTwo setHidden:YES];
//    [viewThree setHidden:YES];

 [self hideShowBottomBar];
  }

- (void)hideShowBottomBar
{
  BOOL isOne = !viewOne.isHidden;
  BOOL isTwo = !viewTwo.isHidden;
  BOOL isThree = !viewThree.isHidden;

  viewOneWidthConstant = _viewOneWidth.constant;
  viewTwoWidthConstant = _viewTwoWidth.constant;
  viewThreeWidthConstant = _viewThreeWidth.constant;
  viewBottomWidthConstant = _viewBottomWidth.constant;

   if (isOne && isTwo && isThree) {
    // 0    0   0
    _viewOneWidth.constant = viewBottomWidthConstant / 3;
    _viewTwoWidth.constant = viewBottomWidthConstant / 3;
    _viewThreeWidth.constant = viewBottomWidthConstant / 3;
    }
    else if (isOne && isTwo && !isThree) {
     // 0    0   1
    _viewOneWidth.constant = viewBottomWidthConstant / 2;
    _viewTwoWidth.constant = viewBottomWidthConstant / 2;
    _viewThreeWidth.constant = 0;
    }
   else if (isOne && !isTwo && isThree) {
    // 0    1   0
    _viewOneWidth.constant = viewBottomWidthConstant / 2;
    _viewTwoWidth.constant = 0;
    _viewThreeWidth.constant = viewBottomWidthConstant / 2;
    }
    else if (isOne && !isTwo && !isThree) {
    // 0    1   1
    _viewOneWidth.constant = viewBottomWidthConstant;
    _viewTwoWidth.constant = 0;
    _viewThreeWidth.constant = 0;
   }
   else if (!isOne && isTwo && isThree) {
    // 1    0   0
    _viewOneWidth.constant = 0;
    _viewTwoWidth.constant = viewBottomWidthConstant / 2;
    _viewThreeWidth.constant = viewBottomWidthConstant / 2;
   }
   else if (!isOne && isTwo && !isThree) {
    // 1    0   1
    _viewOneWidth.constant = 0;
    _viewTwoWidth.constant = viewBottomWidthConstant;
    _viewThreeWidth.constant = 0;
   }
   else if (!isOne && !isTwo && isThree) {
    // 1    1   0
    _viewOneWidth.constant = 0;
    _viewTwoWidth.constant = 0;
    _viewThreeWidth.constant = viewBottomWidthConstant;
   }
   else if (isOne && isTwo && isThree) {
    // 1    1   1
    _viewOneWidth.constant = 0;
    _viewTwoWidth.constant = 0;
    _viewThreeWidth.constant = 0;
   }
  }

 - (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
 // Dispose of any resources that can be recreated.
 }
 @end

entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici

Espérons que cette logique aidera quelqu'un.


1

Dans mon cas, j'ai défini la constante de la contrainte de hauteur sur 0.0fet également défini la hiddenpropriété sur YES.

Pour afficher à nouveau la vue (avec les sous-vues), j'ai fait le contraire: j'ai défini la constante de hauteur sur une valeur non nulle et défini la hiddenpropriété sur NO.


1

J'utiliserai stackview horizontal. Il peut supprimer le cadre lorsque la sous-vue est masquée.

Dans l'image ci-dessous, la vue rouge est le conteneur réel de votre contenu et dispose d'un espace de fin de 10 points à la vue d'ensemble orange (ShowHideView), puis connectez simplement ShowHideView à IBOutlet et affichez / masquez / supprimez-le par programme.

  1. C'est lorsque la vue est visible / installée.

la vue est visible

  1. C'est lorsque la vue est masquée / non installée.

la vue est masquée / supprimée


1

C'est ma autre solution en utilisant la contrainte de priorité. L'idée est de définir la largeur à 0.

  1. créer une vue conteneur (orange) et définir la largeur. entrez la description de l'image ici

  2. créer une vue de contenu (rouge) et définir l'espace de fin de 10 pt sur superview (orange). Remarquez les contraintes d'espace de fin, il y a 2 contraintes de fin avec une priorité différente. Faible (= 10) et élevée (<= 10). Ceci est important pour éviter toute ambiguïté. entrez la description de l'image ici

  3. Définissez la largeur de la vue orange sur 0 pour masquer la vue. entrez la description de l'image ici


0

Comme l'a suggéré no_scene, vous pouvez certainement le faire en modifiant la priorité de la contrainte lors de l'exécution. Cela a été beaucoup plus facile pour moi car j'avais plusieurs vues de blocage qui devaient être supprimées.

Voici un extrait utilisant ReactiveCocoa:

RACSignal* isViewOneHiddenSignal = RACObserve(self.viewModel, isViewOneHidden);
RACSignal* isViewTwoHiddenSignal = RACObserve(self.viewModel, isViewTwoHidden);
RACSignal* isViewThreeHiddenSignal = RACObserve(self.viewModel, isViewThreeHidden);
RAC(self.viewOne, hidden) = isViewOneHiddenSignal;
RAC(self.viewTwo, hidden) = isViewTwoHiddenSignal;
RAC(self.viewThree, hidden) = isViewThreeHiddenSignal;

RAC(self.viewFourBottomConstraint, priority) = [[[[RACSignal
    combineLatest:@[isViewOneHiddenSignal,
                    isViewTwoHiddenSignal,
                    isViewThreeHiddenSignal]]
    and]
    distinctUntilChanged]
    map:^id(NSNumber* allAreHidden) {
        return [allAreHidden boolValue] ? @(780) : @(UILayoutPriorityDefaultHigh);
    }];

RACSignal* updateFramesSignal = [RACObserve(self.viewFourBottomConstraint, priority) distinctUntilChanged];
[updateFramesSignal
    subscribeNext:^(id x) {
        @strongify(self);
        [self.view setNeedsUpdateConstraints];
        [UIView animateWithDuration:0.3 animations:^{
            [self.view layoutIfNeeded];
        }];
    }];


0

Voici comment je réalignerais mes vues pour obtenir votre solution:

  1. Faites glisser un UIImageView et placez-le vers la gauche.
  2. Faites glisser un UIView et placez-le à droite de UIImageView.
  3. Faites glisser deux UILabels à l'intérieur de cette UIView dont les contraintes de début et de fin sont nulles.
  4. Définissez la contrainte principale de UIView contenant 2 étiquettes sur superview au lieu de UIImagView.
  5. SI UIImageView est masqué, définissez la constante de contrainte principale à 10 px sur superview. Sinon, définissez la constante de contrainte principale sur 10 px + UIImageView.width + 10 px.

J'ai créé ma propre règle. Chaque fois que vous devez masquer / afficher une uiview dont les contraintes pourraient être affectées, ajoutez toutes les sous-vues affectées / dépendantes à l'intérieur d'une uiview et mettez à jour sa constante de contrainte de début / fin / haut / bas par programme.


0

C'est une vieille question mais j'espère que ça va aider. Venant d'Android, dans cette plate-forme, vous avez une méthode pratique isVisiblepour le cacher de la vue, mais pas non plus le cadre pris en compte lorsque la mise en page automatique dessine la vue.

en utilisant extension et "extend" uiview, vous pouvez faire une fonction similaire dans ios (vous ne savez pas pourquoi il ne l'est pas déjà dans UIKit) ici une implémentation dans swift 3:

    func isVisible(_ isVisible: Bool) {
        self.isHidden = !isVisible
        self.translatesAutoresizingMaskIntoConstraints = isVisible
        if isVisible { //if visible we remove the hight constraint 
            if let constraint = (self.constraints.filter{$0.firstAttribute == .height}.first){
                self.removeConstraint(constraint)
            }
        } else { //if not visible we add a constraint to force the view to have a hight set to 0
            let height = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal , toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: 0)
            self.addConstraint(height)
        }
        self.layoutIfNeeded()
    }

0

la bonne façon de le faire est de désactiver les contraintes avec isActive = false. notez cependant que la désactivation d'une contrainte la supprime et la libère, vous devez donc disposer de sorties solides pour elles.


0

La solution la plus simple consiste à utiliser UIStackView (horizontal). Ajouter à la vue de la pile: première vue et deuxième vue avec étiquettes. Définissez ensuite la propriété isHidden de la première vue sur false. Toutes les contraintes seront calculées et mises à jour automatiquement.


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.