web-dev-qa-db-fra.com

setNeedsLayout vs setNeedsUpdateConstraints et layoutIfNeeded vs updateConstraintsIfNeeded

Je sais que la chaîne de mise en page automatique consiste essentiellement en 3 processus différents.

  1. mise à jour des contraintes
  2. les vues de mise en page (voici où nous obtenons le calcul des cadres)
  3. afficher

Ce qui n’est pas tout à fait clair pour moi, c’est la différence intérieure entre -setNeedsLayout et -setNeedsUpdateConstraints. De Apple Docs:

setNeedsLayout

Appelez cette méthode sur le thread principal de votre application lorsque vous souhaitez ajuster la présentation des sous-vues d’une vue. Cette méthode prend note de la demande et retourne immédiatement. Comme cette méthode ne force pas une mise à jour immédiate, mais attend le prochain cycle de mise à jour, vous pouvez l'utiliser pour invalider la mise en page de plusieurs vues avant la mise à jour de l'une de ces vues. Ce comportement vous permet de consolider toutes vos mises à jour de présentation en un cycle de mise à jour, ce qui est généralement meilleur pour les performances.

setNeedsUpdateConstraints

Lorsqu'une propriété de votre vue personnalisée change d'une manière qui aurait un impact sur les contraintes, vous pouvez appeler cette méthode pour indiquer que les contraintes doivent être mises à jour ultérieurement. Le système appelle ensuite updateConstraints dans le cadre de sa passe de présentation normale. La mise à jour simultanée des contraintes juste avant leur utilisation vous évite de recalculer inutilement les contraintes lorsque plusieurs modifications sont apportées à votre vue entre les étapes de présentation.

Lorsque je souhaite animer une vue après avoir modifié une contrainte et animer les modifications, j'appelle généralement par exemple:

[UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.modifConstrView setNeedsUpdateConstraints];
        [self.modifConstrView layoutIfNeeded];
    } completion:NULL];

J'ai découvert que si j'utilise -setNeedsLayout au lieu de -setNeedsUpdateConstraints tout fonctionne comme prévu, mais si je change de -layoutIfNeeded avec -updateConstraintsIfNeeded, l'animation ne se produira pas.
J'ai essayé de tirer ma propre conclusion:

  • -updateConstraintsIfNeeded ne met à jour que les contraintes mais ne force pas la mise en page à entrer dans le processus, les images d'origine sont donc conservées
  • -setNeedsLayout appelle également la méthode -updateContraints

Alors, quand est-il possible d'utiliser l'un au lieu de l'autre? et à propos des méthodes de présentation, dois-je les appeler sur la vue modifiée dans une contrainte ou sur la vue parent?

218
Andrea

Vos conclusions sont correctes. Le schéma de base est le suivant:

  • setNeedsUpdateConstraints s'assure qu'un futur appel à updateConstraintsIfNeeded appelle updateConstraints.
  • setNeedsLayout s'assure qu'un futur appel à layoutIfNeeded appelle layoutSubviews.

Lorsque layoutSubviews est appelé, il appelle également updateConstraintsIfNeeded. Il est donc rarement nécessaire de l'appeler manuellement, selon mon expérience. En fait, je ne l’ai jamais appelée, sauf lors du débogage de maquettes.

La mise à jour des contraintes à l'aide de setNeedsUpdateConstraints est assez rare aussi, objc.io - une information à connaître sur les autolayouts - dit :

Si quelque chose change plus tard qui invalide l’une de vos contraintes, vous devez immédiatement la retirer et appeler setNeedsUpdateConstraints. En fait, c’est le seul cas où vous devriez avoir à déclencher un passage de mise à jour de contrainte.

De plus, d'après mon expérience, je n'ai jamais eu à invalider de contraintes ni à définir la setNeedsLayout dans la ligne suivante du code, car les nouvelles contraintes demandent à peu près une nouvelle présentation.

Les règles de base sont les suivantes:

  • Si vous avez manipulé directement des contraintes, appelez setNeedsLayout.
  • Si vous avez modifié certaines conditions (telles que offset ou smth) qui modifieraient les contraintes dans votre méthode updateConstraints remplacée (méthode recommandée pour modifier les contraintes, au fait), appelez setNeedsUpdateConstraints et la plupart du temps, setNeedsLayout après cela.
  • Si vous avez besoin que l’une des actions ci-dessus ait un effet immédiat, par exemple. lorsque vous avez besoin d’apprendre une nouvelle hauteur de cadre après une passe d’agencement, ajoutez-le avec un layoutIfNeeded.

De plus, dans votre code d'animation, j'estime que setNeedsUpdateConstraints n'est pas nécessaire, car les contraintes sont mises à jour manuellement avant l'animation, et l'animation ne fait que redistribuer la vue en fonction des différences entre l'ancienne et la nouvelle.

255
coverback

Le répondre par coverback est plutôt correct. Cependant, je voudrais ajouter quelques détails supplémentaires.

Vous trouverez ci-dessous le schéma d’un cycle typique d’UIView qui explique d’autres comportements:

UIView's Lifecycle

  1. J'ai découvert que si j'utilise -setNeedsLayout au lieu de -setNeedsUpdateConstraints tout fonctionne comme prévu, mais si je change de -layoutIfNeeded avec -updateConstraintsIfNeeded , l'animation ne se produira pas.

updateConstraints ne fait généralement rien. Il résout simplement les contraintes, il ne les applique pas jusqu'à ce que layoutSubviews soit appelé. Donc, l'animation nécessite un appel à layoutSubviews.

  1. setNeedsLayout appelle également la méthode -updateContraints

Non ce n'est pas nécessaire. Si vos contraintes n'ont pas été modifiées, UIView ignorera l'appel de updateConstraints. Vous devez appeler explicitement setNeedsUpdateConstraint pour modifier les contraintes dans le processus.

Pour appeler updateConstraints, vous devez procéder comme suit:

[view setNeedsUpdateConstraints];
[view setNeedsLayout]; 
[view layoutIfNeeded];
84
Kunal Balani