J'ai une disposition à quatre boutons. En portrait, ils doivent être montrés l'un au-dessus de l'autre. En paysage, ils doivent être en deux colonnes avec chacune deux boutons.
J'implémente les boutons dans le code - des trucs vraiment simples:
UIButton *btn1 = [[UIButton alloc] init];
[self.view addSubview: btn1];
UIButton *btn2 = [[UIButton alloc] init];
[self.view addSubview: btn2];
UIButton *btn3 = [[UIButton alloc] init];
[self.view addSubview: btn3];
UIButton *btn4 = [[UIButton alloc] init];
[self.view addSubview: btn4];
NSDictionary *views = NSDictionaryOfVariableBindings(btn1, btn2, btn3, btn4);
[btn1 setTranslatesAutoresizingMaskIntoConstraints:NO];
[btn2 setTranslatesAutoresizingMaskIntoConstraints:NO];
[btn3 setTranslatesAutoresizingMaskIntoConstraints:NO];
[btn4 setTranslatesAutoresizingMaskIntoConstraints:NO];
// portrait constraints
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn1]-(50)-|"
options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn2]-(50)-|"
options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn3]-(50)-|"
options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn4]-(50)-|"
options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[btn1]-[btn2]-[btn3]-[btn4]-(50)-|"
options:0 metrics:nil views:views]];
C'est évidemment la configuration pour la mise en page portrait. J'aurais l'habitude d'avoir déterminé l'appareil et son orientation pour faire un étui spécifique pour iPad et iPhone dans leurs orientations respectives. Mais maintenant, nous sommes censés utiliser des classes de taille. Comment puis-je déterminer si la classe de taille est "compacte" ... et ainsi définir les contraintes appropriées?
En attendant, j'ai trouvé une bonne solution. Étant donné que cette question a tant de votes positifs, j'ai pensé la décrire rapidement. J'ai été inspiré à cette solution par une session de la WWDC.
Je suis passé à Swift alors veuillez excuser que le code sera en Swift - le concept est cependant le même pour Obj-C.
Vous commencez par déclarer trois tableaux de contraintes:
// Constraints
private var compactConstraints: [NSLayoutConstraint] = []
private var regularConstraints: [NSLayoutConstraint] = []
private var sharedConstraints: [NSLayoutConstraint] = []
Et puis vous remplissez les contraintes en conséquence. Vous pouvez par exemple le faire dans une fonction distincte que vous appelez à partir de viewDidLoad
ou vous le faites directement dans viewDidLoad
.
sharedConstraints.append(contentsOf: [
btnStackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
...
])
compactConstraints.append(contentsOf: [
btnStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.7),
...
])
regularConstraints.append(contentsOf: [
btnStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.4),
...
])
L'important est de basculer entre les classes de taille et d'activer/désactiver les contraintes appropriées.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if (!sharedConstraints[0].isActive) {
// activating shared constraints
NSLayoutConstraint.activate(sharedConstraints)
}
if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular {
if regularConstraints.count > 0 && regularConstraints[0].isActive {
NSLayoutConstraint.deactivate(regularConstraints)
}
// activating compact constraints
NSLayoutConstraint.activate(compactConstraints)
} else {
if compactConstraints.count > 0 && compactConstraints[0].isActive {
NSLayoutConstraint.deactivate(compactConstraints)
}
// activating regular constraints
NSLayoutConstraint.activate(regularConstraints)
}
}
Je sais que les contraintes ne correspondent pas à celles de la question. Mais les contraintes elles-mêmes ne sont pas pertinentes. L'essentiel est de savoir comment basculer entre deux ensembles de contraintes en fonction de la classe de taille.
J'espère que cela t'aides.
Vous pouvez examiner la collection de traits de la vue pour déterminer sa classe de taille horizontale et verticale.
if (self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
...
}
Implémentez le traitCollectionDidChange:
méthode à appeler automatiquement lorsqu'un trait change en raison de l'autorotation.
Pour plus d'informations, consultez ITraitCollection Class Reference et ITraitEnvironment Protocol Reference .
Code Swift 4 pour la réponse acceptée:
if (self.view.traitCollection.horizontalSizeClass == .compact) {
...
}
traitCollection ne fonctionne que sur iOS8. Votre application se bloquera donc sur iOS7. Utilisez le code ci-dessous pour prendre en charge iOS7 et iOS8
if ([self.view respondsToSelector:@selector(traitCollection)]){
if (self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
...
}
}