web-dev-qa-db-fra.com

Ressorts dans la mise en page automatique: répartissez les vues uniformément, avec des contraintes, dans Xcode 5

Je comprends l'ancienne méthode Struts and Springs d'alignement, de dimensionnement et de distribution des vues dans Interface Builder. Cependant, je n'arrive pas à comprendre comment répartir uniformément les vues en utilisant la disposition automatique avec Xcode 5. Il y avait un moyen de le faire en utilisant Xcode 4, mais cette option a disparu.

J'ai 7 boutons disposés dans une pile verticale. Sur une mise en page de 3,5 pouces, cela a fière allure. Lorsque je prévisualise l'écran dans la disposition de 4 pouces, tous les boutons restent bien serrés et il y a une grande quantité d'espace sous le dernier bouton.

Je veux qu'ils restent à la même hauteur, mais je veux que l'espace entre eux puisse fléchir afin qu'ils puissent s'étendre sur l'écran.

enter image description here

J'ai pu obtenir la hauteur des boutons pour fléchir et remplir l'espace, mais ce n'est pas mon comportement souhaité. J'aimerais apprendre à utiliser la disposition automatique pour remplacer mon ancien comportement de Springs, mais je n'arrive pas à trouver de moyen de le faire via Interface Builder.

Je suis d'accord avec le bouton supérieur étant soit un espace fixe du bord supérieur ou un espace proportionnel du bord supérieur, de même pour le bouton inférieur et le bord inférieur. Celles-ci sont moins importantes pour moi, je suis bon avec les deux.

Mais j'ai vraiment besoin de comprendre comment répartir uniformément l'espace supplémentaire entre chacun des éléments de la vue.

42
Kenny Wyland

[~ # ~] modifier [~ # ~] Notez que dans iOS 9 cette technique deviendra inutile, car un UIStackView effectuera automatiquement la distribution. J'ajouterai ne autre réponse expliquant comment cela fonctionne.

Comment effectuer une distribution uniforme à l'aide de la mise en page automatique

La façon la plus simple de le faire dans Interface Builder seul (plutôt que de construire des contraintes dans le code) est d'utiliser des vues "spacer":

  1. Positionnez absolument les boutons du haut et du bas.

  2. Placez des vues d'espacement entre tous les boutons. Utilisez des contraintes pour les positionner horizontalement (leur centrage horizontal est le plus simple) et pour définir leurs largeurs.

  3. Créez des contraintes entre chaque bouton et la vue d'espacement au-dessus et en dessous, avec une constante de 0.

  4. Sélectionnez maintenant toutes les vues d'espacement et définissez leurs hauteurs pour qu'elles soient égales.

La première capture d'écran me montre la configuration de cela dans IB:

enter image description here

Je n'ai délibérément pas corrigé les "vues mal placées" parce que je veux que vous voyiez à quoi cela ressemble pendant que je conçois les contraintes. Voici le résultat sur un écran de 4 pouces et 3,5 pouces:

enter image description here

J'ai laissé les vues d'espacement noires, juste pour vous montrer comment cette technique fonctionne, mais bien sûr, dans la vraie vie, vous les rendriez transparentes et donc invisibles! Ainsi, l'utilisateur ne voit que vos boutons, répartis uniformément sur chaque hauteur d'écran.

La raison de l'utilisation de cette technique est que, bien que la notion d'égalité effectue la distribution des valeurs que vous demandez, les contraintes ne peuvent appliquer l'égalité qu'entre les aspects des vues; nous avons donc besoin des vues supplémentaires (les vues d'espacement) afin d'avoir des choses que nous pouvons faire égales à d'autres choses (ici, les hauteurs des vues d'espacement).

Autres approches

De toute évidence, une approche plus flexible consiste à affecter les contraintes dans le code. Cela peut sembler intimidant, mais il existe de nombreux codes tiers pour vous aider, tels que ce genre de chose .

Par exemple, si nous avons une vue d'ensemble (éventuellement invisible) dont la hauteur agit comme une limite pour dicter la distribution verticale maximale de nos quatre boutons, nous pouvons épingler leurs sommets au centre vertical de cette vue d'ensemble avec un constant de 0 mais un multiplier de 0.000001, 0.666667, 1.33333, et 2.0 respectivement (si nous avons quatre boutons); maintenant, les boutons resteront distribués verticalement même si la vue d'ensemble change de taille en réponse à la hauteur de l'écran ou autre. [Dans Xcode 5.1, il sera possible de configurer cela dans Interface Builder, mais dans les versions antérieures de Xcode, ce n'est pas possible.]

84
matt

Dans iOS 9/Xcode 7, ce problème sera résolu de manière triviale dans IB. Sélectionnez simplement les boutons (ou ce que vous souhaitez distribuer verticalement) et choisissez Editeur> Incorporer dans> Vue de la pile. Ensuite, vous configurez simplement la vue de la pile:

  • Fournissez des contraintes qui positionnent et dimensionnent la vue de la pile elle-même. Par exemple, épinglez les quatre bords de la vue de pile aux quatre bords de sa vue d'ensemble.

  • Définissez les attributs de la vue de pile. Dans ce cas, nous voulons l'axe vertical, l'alignement de remplissage, la distribution d'espacement égal.

C'est tout! Cependant, vous pouvez être curieux de savoir comment cela fonctionne, car il est toujours possible de faire la même chose manuellement dans le code. Une vue de pile effectue la distribution, non pas en insérant l'espaceur vues, mais en insérant l'espaceur guides. Un guide (un UILayoutGuide) est un objet léger qui se comporte comme une vue aux fins des contraintes de mise en page, mais n'est pas une vue et ne doit donc pas être rendu invisible et ne porte aucun des frais généraux d'une vue.

Pour illustrer, je vais faire en code ce que fait la vue de pile. Supposons que nous ayons quatre vues à distribuer verticalement. Nous leur attribuons des contraintes pour tout sauf leur distribution:

  • Ils ont tous des contraintes de hauteur absolues

  • Leur gauche est épinglée à gauche de la superview, et leur droite est épinglée à droite de la superview

  • Le haut de la vue de dessus est épinglé en haut de la vue d'ensemble, et le bas de la vue de dessous est épinglé en bas de la vue d'ensemble

Supposons maintenant que nous ayons des références aux quatre vues comme views, un tableau. Alors:

let guides = [UILayoutGuide(), UILayoutGuide(), UILayoutGuide()]
for guide in guides {
    self.view.addLayoutGuide(guide)
}
NSLayoutConstraint.activateConstraints([
    // guide heights are equal
    guides[1].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor),
    guides[2].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor),
    // guide widths are arbitrary, let's say 10
    guides[0].widthAnchor.constraintEqualToConstant(10),
    guides[1].widthAnchor.constraintEqualToConstant(10),
    guides[2].widthAnchor.constraintEqualToConstant(10),
    // guide left is arbitrary, let's say superview margin
    guides[0].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
    guides[1].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
    guides[2].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
    // bottom of each view is top of following guide
    views[0].bottomAnchor.constraintEqualToAnchor(guides[0].topAnchor),
    views[1].bottomAnchor.constraintEqualToAnchor(guides[1].topAnchor),
    views[2].bottomAnchor.constraintEqualToAnchor(guides[2].topAnchor),
    // top of each view is bottom of preceding guide
    views[1].topAnchor.constraintEqualToAnchor(guides[0].bottomAnchor),
    views[2].topAnchor.constraintEqualToAnchor(guides[1].bottomAnchor),
    views[3].topAnchor.constraintEqualToAnchor(guides[2].bottomAnchor)
])

(Évidemment, je pourrais rendre ce code plus mignon et plus court en utilisant des boucles, mais j'ai délibérément déroulé les boucles pour plus de clarté, afin que vous puissiez voir le modèle et la technique.)

10
matt