web-dev-qa-db-fra.com

Quand puis-je activer / désactiver les contraintes de mise en page?

J'ai défini plusieurs ensembles de contraintes dans IB et je souhaite basculer par programme entre eux en fonction de l'état. Il existe une collection constraintsA qui sont toutes marquées comme installées à partir d'IB et une collection constraintsB qui sont toutes désinstallées dans IB.

Je peux par programme basculer entre les deux ensembles comme suit:

NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)

Mais ... je ne peux pas comprendre quand faire cela. Il semble que je devrais pouvoir le faire une fois dans viewDidLoad, mais je ne parviens pas à le faire fonctionner. J'ai essayé d'appeler view.updateConstraints() et view.layoutSubviews() après avoir défini les contraintes, mais en vain.

J'ai constaté que si je définissais les contraintes dans viewDidLayoutSubviews tout fonctionnait comme prévu. Je suppose que j'aimerais savoir deux choses ...

  1. Pourquoi ai-je ce comportement?
  2. Est-il possible d'activer/désactiver les contraintes de viewDidLoad?
88
tybro0103

J'active et désactive NSLayoutConstraints dans viewDidLoad, et je n'ai aucun problème avec cela. Donc ça marche. Il doit y avoir une différence de configuration entre votre application et la mienne :-)

Je vais juste décrire ma configuration - peut-être que cela peut vous donner une piste:

  1. J'ai configuré @IBOutlets pour toutes les contraintes que je dois activer/désactiver.
  2. Dans la ViewController, je sauvegarde les contraintes dans des propriétés de classe qui ne sont pas faibles. La raison en est que j’ai constaté qu’après la désactivation d’une contrainte, je ne pouvais plus la réactiver - c’était nul. Donc, il semble être supprimé lorsqu'il est désactivé.
  3. Je n'utilise pas NSLayoutConstraint.deactivate/activate comme vous, j'utilise plutôt constraint.active = YES/NO.
  4. Après avoir défini les contraintes, j'appelle view.layoutIfNeeded().
166
Joachim Bøggild

Peut-être que vous pourriez vérifiez votre @properties, remplacez weak par strong.

Parfois, c'est parce que active = NO définit self.yourConstraint = nil, de sorte que vous ne puissiez plus utiliser self.yourConstraint.

42
Leo
override func viewDidLayoutSubviews() {
// do it here, after constraints have been materialized
}
29
Tony Swiftguy

Je pense que le problème que vous rencontrez est dû au fait que des contraintes n’ont pas été ajoutées à leurs vues jusqu’à ce que AFTER viewDidLoad() soit appelé. Vous avez un certain nombre d'options:

A) Vous pouvez connecter vos contraintes de présentation à un IBOutlet et y accéder dans votre code par ces références. Étant donné que les prises sont connectées avant le début de viewDidLoad(), les contraintes doivent être accessibles et vous pouvez continuer à les activer et les désactiver.

B) Si vous souhaitez utiliser la fonction constraints() de UIView pour accéder aux diverses contraintes, vous devez attendre que viewDidLayoutSubviews() démarre et le fasse ici, car c'est le premier point après créer un contrôleur de vue à partir d'une nib qui aura des contraintes installées. N'oubliez pas d'appeler layoutIfNeeded() lorsque vous avez terminé. Cela présente l'inconvénient que la passe de présentation sera effectuée deux fois s'il y a des modifications à appliquer et vous devez vous assurer qu'il n'y a aucune possibilité qu'une boucle infinie soit déclenchée.

Petit mot d’avertissement: les contraintes désactivées ne sont PAS renvoyées par le signe constraints()! Cela signifie que si vous désactivez une contrainte dans l’intention de la réactiver ultérieurement, vous devrez conserver une référence.

C) Vous pouvez oublier l'approche du storyboard et ajouter vos contraintes manuellement à la place. Puisque vous faites cela dans viewDidLoad(), je suppose que l’intention est de ne le faire qu’une seule fois pendant toute la durée de vie de l’objet plutôt que de changer la disposition à la volée. C’est donc une méthode acceptable.

14
Ash

Vous pouvez également ajuster la propriété priority pour les "activer" et les "désactiver" (valeur 750 à activer et 250 à désactiver par exemple). Pour une raison quelconque, le changement de active BOOL n'a eu aucun effet sur mon interface utilisateur. Pas besoin de layoutIfNeeded et peut être défini et modifié à viewDidLoad ou à tout moment par la suite.

9
user2387149

Le bon moment pour désactiver les contraintes non utilisées:

-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    self.myLittleConstraint.active = NO;
}

Gardez à l'esprit que viewWillLayoutSubviews pourrait être appelé plusieurs fois, donc pas de calculs lourds ici, d'accord?

Remarque: si vous souhaitez réactiver certaines contraintes ultérieurement, stockez-les toujours strong référence.

7
Laszlo

J'ai trouvé aussi longtemps que vous définissez les contraintes normales dans le remplacement de - (void)updateConstraints (objectif C), avec une référence strong pour l'initialité utilisée, des contraintes actives et non actives. Et ailleurs dans le cycle de visualisation, désactivez et/ou activez ce dont vous avez besoin, puis appelez layoutIfNeeded et ne rencontrez aucun problème.

L'essentiel est de ne pas réutiliser constamment le remplacement de updateConstraints et de séparer les activations des contraintes, tant que vous appelez updateConstraints après votre première initialisation et mise en page. Cela semble avoir de l'importance après cela, où dans le cycle de vue.

1
elliotrock

Lors de la création d'une vue, les méthodes de cycle de vie suivantes sont appelées dans l'ordre:

  1. loadView
  2. viewDidLoad
  3. voirBienapparaître
  4. viewWillLayoutSubviews
  5. viewDidLayoutSubviews
  6. viewDidAppear

Maintenant à vos questions.

  1. Pourquoi ai-je ce comportement?

Réponse: étant donné que lorsque vous essayez de définir les contraintes sur les vues dans viewDidLoad, la vue n'a pas de limites, vous ne pouvez donc pas définir de contraintes. Ce n'est qu'après viewDidLayoutSubviews que les limites de la vue sont finalisées.

  1. Est-il possible d'activer/désactiver les contraintes de viewDidLoad?

Réponse: Non. Raison expliquée ci-dessus.

1
Sumeet