web-dev-qa-db-fra.com

Implémentation par programme de deux dispositions différentes à l'aide de classes de taille

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?

38
Joseph

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.

37
Joseph

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 .

35
user4151918

Code Swift 4 pour la réponse acceptée:

if (self.view.traitCollection.horizontalSizeClass == .compact) {
...
}
10
RemyDCF

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) {
    ...
    }

}
2
Kirit Vaghela