web-dev-qa-db-fra.com

Où devrais-je définir des contraintes de report automatique lors de la création de vues par programme

Je vois différents exemples où des contraintes sont définies. Certains les définissent dans viewDidLoad/loadView (après l'ajout de la sous-vue). D'autres les définissent dans la méthode updateViewConstraints, qui est appelée par viewDidAppear.

Lorsque j'essaie de définir des contraintes dans updateViewContraints, la disposition peut être instable, par exemple. léger délai avant que la vue apparaisse. De plus, si j’utilise cette méthode, devrais-je d'abord effacer les contraintes existantes, à savoir [self.view [removeConstraints:self.view.constraints]?

74
Heisenberg

J'ai configuré mes contraintes dans viewDidLoadloadView (je cible iOS> = 6). updateViewConstraints est utile pour changer les valeurs de contraintes, par exemple. si une contrainte dépend de l'orientation de l'écran (je sais que c'est une mauvaise pratique), vous pouvez changer sa constant dans cette méthode.

L'ajout de contraintes dans viewDidLoad est indiqué lors de la session _/"Introduction à la mise en page automatique pour iOS et OS X" (WWDC 2012), à partir de 39:22. Je pense que c'est une des choses qui sont dites pendant les conférences mais qui ne figurent pas dans la documentation.

UPDATE: J'ai remarqué la mention de la mise en place de contraintes dans Gestion des ressources dans les contrôleurs de vue :

Si vous préférez créer des vues par programme, au lieu d’utiliser un vous le faites en remplaçant la variable loadView.__ de votre contrôleur de vue. méthode. Votre implémentation de cette méthode devrait faire ce qui suit:

(...)

3.Si vous utilisez la disposition automatique, attribuez des contraintes suffisantes à chacun des fichiers les vues que vous venez de créer pour contrôler la position et la taille de votre fichier vues. Sinon, implémentez viewWillLayoutSubviews et viewDidLayoutSubviews méthodes pour ajuster les cadres des sous-vues dans la hiérarchie des vues. Voir «Redimensionnement des vues du contrôleur de vue».

UPDATE 2: Au cours de la WWDC 2015 Apple a donné une nouvelle explication de updateConstraints et updateViewConstraints usage recommandé:

En réalité, tout cela est un moyen pour les vues d’avoir la possibilité d’apporter des modifications aux contraintes juste à temps pour la prochaine passe, mais ce n’est souvent pas nécessaire.

Toute la configuration initiale de vos contraintes devrait idéalement se dérouler dans Interface Builder.

Ou si vous estimez vraiment que vous devez affecter vos contraintes par programme, un emplacement comme viewDidLoad est bien meilleur.

Les contraintes de mise à jour concernent uniquement le travail à répéter périodiquement.

En outre, il est assez simple de simplement modifier les contraintes lorsque vous en ressentez le besoin; alors que, si vous séparez cette logique de l’autre code qui lui est lié et que vous la déplacez dans une méthode distincte qui sera exécutée ultérieurement, votre code devient beaucoup plus difficile à suivre; , il sera beaucoup plus difficile à comprendre pour les autres.

Alors, quand auriez-vous besoin d'utiliser des contraintes de mise à jour?

Eh bien, cela se résume à la performance.

Si vous trouvez que le changement de vos contraintes en place est trop lent, les contraintes de mise à jour pourraient peut-être vous aider.

Il s'avère que la modification d'une contrainte dans les contraintes de mise à jour est en réalité plus rapide que la modification d'une contrainte à d'autres moments.

La raison en est que le moteur est capable de traiter tous les changements de contrainte intervenant dans cette passe sous forme de lot.

100
Arek Holko

Je recommande de créer un BOOL et de les définir dans le -updateConstraints de UIView (ou -updateViewConstraints pour UIViewController). 

-[UIView updateConstraints] : (documents Apple)

Les vues personnalisées qui définissent elles-mêmes les contraintes doivent le faire en remplaçant cette méthode.

-updateConstraints et -updateViewConstraints peuvent être appelés plusieurs fois au cours de la vie d'une vue. Par exemple, si vous appelez setNeedsUpdateConstraints dans une vue, cela se produira. Par conséquent, vous devez vous assurer que la création et l’activation de contraintes de duplication ne sont pas activées. Assurez-vous de désactiver/supprimer les contraintes existantes avant de créer et d’en activer de nouvelles.

Par exemple:

  - (void)updateConstraints {  // for view controllers, use -updateViewConstraints

         if (!_hasLoadedConstraints) {
              _hasLoadedConstraints = YES;
             // create your constraints
         }
         [super updateConstraints];
    }

Merci à @fresidue dans les commentaires pour signaler que la documentation d'Apple recommande d'appeler super comme dernière étape. Si vous appelez super avant de modifier certaines contraintes, vous risquez de rencontrer une exception d'exécution (crash).

31
BooRanger

Cela devrait être fait dans ViewDidLoad, conformément à la vidéo WWDC d’Apple et à la documentation. 

Aucune idée pourquoi les gens recommandent updateConstraints. Si vous utilisez updateConstraints, vous rencontrerez des problèmes avec NSAutoresizingMaskLayoutConstraint avec redimensionnement automatique car vos vues ont déjà pris en compte les masques automatiques. Vous devrez les supprimer dans updateConstraints pour que votre travail fonctionne. 

UpdateConstraints doit être conçu pour cela, lorsque vous devez les "mettre à jour", apporter des modifications, etc. à partir de votre configuration initiale.

4
BluelineCoding

Vous pouvez les définir dans viewWillLayoutSubviews: too:

 override func viewWillLayoutSubviews() {

    if(!wasViewLoaded){
        wasViewLoaded = true

        //update constraint

        //also maybe add a subview            
    }
}
1
Andre Simon

J'ai cette solution pour changer les contraintes avant que ceux qui sont dans le storyboard ne soient chargés. Cette solution supprime tout retard après le chargement de la vue.

-(void)updateViewConstraints{

    dispatch_async(dispatch_get_main_queue(), ^{

            //Modify here your Constraint -> Activate the new constraint and deactivate the old one

            self.yourContraintA.active = true;
            self.yourContraintB.active= false;
            //ecc..
           });

    [super updateViewConstraints]; // This must be the last thing that you do here -> if! ->Crash!
}
1
Davide

Faites-le en vue a mis en page la méthode des sous-vues

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
}
1
Kit

Cela a fonctionné pour moi:

Swift 4.2

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

// Modify your constraints in here

  ...

}

Bien honnêtement, je ne suis pas sûr que cela en vaille la peine. Il semble un peu plus lent à charger que dans viewDidLoad (). Je voulais juste les sortir de ce dernier, parce que ça devient énorme.

0
Michele Dall'Agata