J'ai mis en place plusieurs sets de contraintes dans IB, et je voudrais basculer par programme entre eux en fonction de l'état. Il y a une collection de sorties de constraintsA
toutes marquées comme installées à partir de IB, et une collection de sorties de constraintsB
qui sont toutes désinstallées dans IB.
Je peux basculer par programme entre les deux sets comme suit:
NSLayoutConstraint.deactivateConstraints(constraintsA) NSLayoutConstraint.activateConstraints(constraintsB)
Mais … je ne peux pas savoir quand faire ça. Il semble que je devrais pouvoir le faire une fois dans viewDidLoad
, mais je ne peux 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 trouvé que si je définis les contraintes dans viewDidLayoutSubviews
tout fonctionne comme prévu. Je suppose que j'aimerais savoir deux choses …
J'active et désactive NSLayoutConstraints
dans viewDidLoad
, et je n'ai aucun problème avec ça. 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 idée:
@IBOutlets
pour toutes les contraintes dont j'ai besoin pour activer / désactiver. ViewController
, je sauvegarde les contraintes dans les propriétés de class qui ne sont pas faibles. La raison en est que j'ai trouvé qu'après avoir désactivé une contrainte, je ne pouvais pas la réactiver – c'était nul. Donc, il semble être supprimé lorsqu'il est désactivé. NSLayoutConstraint.deactivate/activate
comme vous, j'utilise constraint.active = YES
/ NO
place. view.layoutIfNeeded()
. override func viewDidLayoutSubviews() { // do it here, after constraints have been materialized }
Peut-être pourriez-vous vérifier vos @properties
, replace weak
par strong
.
Parfois, parce que active = NO
définissez self.yourContraint = nil
, de sorte que vous ne puissiez plus utiliser self.yourContraint
.
Je crois que le problème que vous éprouvez est dû aux contraintes n'étant pas ajoutées à leurs vues jusqu'à viewDidLoad()
est appelé. Vous avez un certain nombre d'options:
A) Vous pouvez connecter vos contraintes de disposition à un IBOutlet et y accéder dans votre code par ces references. Puisque les sockets sont connectées avant le viewDidLoad()
, les contraintes doivent être accessibles et vous pouvez continuer à les activer et les désactiver.
B) Si vous souhaitez utiliser la fonction constraints()
UIView pour accéder aux différentes contraintes, vous devez attendre que viewDidLayoutSubviews()
démarre et le fasse, car c'est le premier point après avoir créé un controller de vue à partir d'une plume qu'il aura toutes les contraintes installées. N'oubliez pas d'appeler layoutIfNeeded()
lorsque vous avez terminé. Cela présente l'inconvénient que la passe de layout 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.
Un petit mot d'avertissement: les contraintes désactivées ne sont pas returnnées par la méthode constraints()
! Cela signifie que si vous désactivez une contrainte avec l'intention de la réactiver plus tard, vous devrez garder une reference à celle-ci.
C) Vous pouvez oublier l'approche de storyboard et append vos contraintes manuellement à la place. Puisque vous faites cela dans viewDidLoad()
je suppose que l'intention est de ne le faire qu'une fois pour toute la durée de vie de l'object plutôt que de changer la layout à la volée, donc cela devrait être une méthode acceptable.
Vous pouvez également ajuster la propriété priority
pour "activer" et "les désactiver" (valeur 750 pour activer et 250 pour désactiver par exemple). Pour une raison quelconque, la modification du BOOL active
n'a eu aucun effet sur mon interface user. Pas besoin de layoutIfNeeded
et peut être défini et modifié à viewDidLoad ou à tout moment après cela.
Le bon moment pour désactiver les contraintes inutilisé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?
Note: si vous voulez ré-activer certaines contraintes plus tard, gardez-y toujours strong
reference strong
.
J'ai trouvé aussi longtime que vous avez défini les contraintes normales dans le rlocation de - (void)updateConstraints
(objective c), avec une reference strong
pour l'initialité utilisée contraintes actives et inactives. Et ailleurs dans le cycle de vue désactiver et / ou activer ce dont vous avez besoin, puis en appelant layoutIfNeeded
, vous ne devriez avoir aucun problème.
L'essentiel n'est pas de réutiliser constamment le rlocation de updateConstraints
et de séparer les activations des contraintes, tant que vous appelez updateConstraint
s après votre première initialisation et layout. Cela semble importer après cela où dans le cycle de vue.
Lors de la création d'une vue, les methods de cycle de vie suivantes sont appelées dans l'ordre:
Maintenant à vos questions.
- Pourquoi ai-je ce comportement?
Réponse: Parce que lorsque vous essayez de définir les contraintes sur les vues dans viewDidLoad
la vue n'a pas ses limites, donc les contraintes ne peuvent pas être définies. C'est seulement après viewDidLayoutSubviews
que les limites de la vue sont finalisées.
- Est-il possible d'activer / désactiver les contraintes de viewDidLoad?
Réponse: Non. Raison expliquée ci-dessus.