Est-il possible de modifier les contraintes lors de la rotation de l'appareil? Comment pourrait-on y parvenir?
Un exemple simple pourrait être deux images qui, en portrait, sont empilées l'une au-dessus de l'autre, mais en paysage sont côte à côte.
Si ce n'est pas possible, comment pourrais-je accomplir cette disposition?
Je construis mes vues et contraintes dans le code et n'utilise pas le générateur d'interface.
Edit: En utilisant le nouveau concept de Classes de taille introduit dans Xcode 6, vous pouvez configurez facilement différentes contraintes pour des classes de taille spécifiques dans Interface Builder. La plupart des appareils (par exemple tous les iPhones actuels) ont une classe de taille verticale Compact en mode paysage.
Il s'agit d'un concept bien meilleur pour les décisions générales de mise en page que de déterminer l'orientation de l'appareil.
Cela étant dit, si vous avez vraiment besoin de connaître l'orientation, UIDevice.currentDevice().orientation
est le chemin à parcourir.
Message d'origine:
Substituez la méthode updateViewConstraints
de UIViewController
pour fournir des contraintes de mise en page pour des situations spécifiques. De cette façon, la mise en page est toujours configurée correctement en fonction de la situation. Assurez-vous qu'ils forment un ensemble complet de contraintes avec celles créées dans le storyboard. Vous pouvez utiliser IB pour configurer vos contraintes générales et marquer celles susceptibles d'être modifiées à supprimer lors de l'exécution.
J'utilise l'implémentation suivante pour présenter un ensemble différent de contraintes pour chaque orientation:
-(void)updateViewConstraints {
[super updateViewConstraints];
// constraints for portrait orientation
// use a property to change a constraint's constant and/or create constraints programmatically, e.g.:
if (!self.layoutConstraintsPortrait) {
UIView *image1 = self.image1;
UIView *image2 = self.image2;
self.layoutConstraintsPortrait = [[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy];
[self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem: image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
[self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
}
// constraints for landscape orientation
// make sure they don't conflict with and complement the existing constraints
if (!self.layoutConstraintsLandscape) {
UIView *image1 = self.image1;
UIView *image2 = self.image2;
self.layoutConstraintsLandscape = [[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy];
[self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
[self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem: image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
}
BOOL isPortrait = UIInterfaceOrientationIsPortrait(self.interfaceOrientation);
[self.view removeConstraints:isPortrait ? self.layoutConstraintsLandscape : self.layoutConstraintsPortrait];
[self.view addConstraints:isPortrait ? self.layoutConstraintsPortrait : self.layoutConstraintsLandscape];
}
Maintenant, tout ce que vous avez à faire est de déclencher une mise à jour des contraintes chaque fois que la situation change. Passer outre willAnimateRotationToInterfaceOrientation:duration:
pour animer la mise à jour des contraintes lors d'un changement d'orientation:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self.view setNeedsUpdateConstraints];
}
L'approche que j'utilise (pour le meilleur ou pour le pire) consiste à définir les deux ensembles de contraintes (portrait et paysage) dans l'éditeur de storyboard.
Pour éviter les avertissements de l'enfer du storyboard, je place tout un ensemble à une priorité de 999, juste pour qu'il ne s'affiche pas rouge partout.
J'ajoute ensuite toutes les contraintes aux collections outlet:
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *portraitConstraints;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *landscapeConstraints;
Enfin, j'implémente la méthode ViewControllers
de viewWillLayout
:
- (void) viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
for (NSLayoutConstraint *constraint in self.portraitConstraints) {
constraint.active = (UIApplication.sharedApplication.statusBarOrientation == UIDeviceOrientationPortrait);
}
for (NSLayoutConstraint *constraint in self.landscapeConstraints) {
constraint.active = (UIApplication.sharedApplication.statusBarOrientation != UIDeviceOrientationPortrait);
}
}
Cela semble fonctionner. Je vraiment souhaite que vous puissiez définir la propriété active par défaut dans l'éditeur de storyboard.
Je suis la même approche que la vôtre (pas de fichiers ni de storyboards). Vous devez mettre à jour vos contraintes dans la méthode updateViewConstraints
(en vérifiant l'orientation du périphérique). Il n'est pas nécessaire d'appeler setNeedsUpdateConstraints
dans updateViewConstraints
car dès que vous changez l'orientation du périphérique, la dernière méthode est appelée automatiquement.
Vous pouvez enregistrer vos contraintes dans une propriété ou une variable en tant que versions portrait et paysage, puis les définir et les supprimer lors de la rotation.
J'ai fait cela en créant mes contraintes dans xib pour la vue initiale, en les affectant à des prises dans le contrôleur de vue. Lors de la rotation, je crée les contraintes alternatives, supprime les sorties mais les conserve, insère les alternatives.
Inversez le processus lors de la rotation arrière.