La mise en page automatique me rend la vie difficile. En théorie, ça allait être vraiment utile quand je suis passé, mais je semble me battre tout le temps.
J'ai fait un projet de démonstration pour essayer de trouver de l'aide. Est-ce que quelqu'un sait comment augmenter ou diminuer uniformément les espaces entre les vues chaque fois que la vue est redimensionnée?
Voici trois étiquettes (espacées manuellement même verticalement):
Ce que je veux, c'est qu'ils redimensionnent leur espacement (pas la taille de la vue) uniformément lorsque je tourne. Par défaut, les vues du haut et du bas s'affichent vers le centre:
Réponses:
Mon approche vous permet donc de le faire dans le constructeur d'interface. Ce que vous faites est de créer des «vues d'espacement» que vous avez définies pour correspondre également aux hauteurs. Ajoutez ensuite des contraintes supérieure et inférieure aux étiquettes (voir la capture d'écran).
Plus précisément, j'ai une contrainte supérieure sur 'Spacer View 1' à superview avec une contrainte de hauteur de priorité inférieure à 1000 et avec Height Equals à toutes les autres 'spacer vues'. 'Spacer View 4' a une contrainte d'espace inférieur à la vue d'ensemble. Chaque étiquette a des contraintes supérieures et inférieures respectives à ses «vues d'espacement» les plus proches.
Remarque: assurez-vous que vous n'avez PAS de contraintes d'espace supérieur / inférieur supplémentaires sur vos étiquettes pour la vue d'ensemble; juste celles des «vues de l'espace». Cela sera satisfaisant puisque les contraintes supérieures et inférieures se trouvent respectivement sur «Space View 1» et «Spacer View 4».
Duh 1: J'ai dupliqué ma vue et je l'ai simplement mise en mode paysage pour que vous puissiez voir que cela fonctionne.
Duh 2: Les «vues d'espacement» auraient pu être transparentes.
Duh 3: Cette approche pourrait être appliquée horizontalement.
la source
REGARDEZ, PAS D'ESPACES!
Sur la base des suggestions de la section commentaires de ma réponse d'origine, en particulier des suggestions utiles de @ Rivera, j'ai simplifié ma réponse d'origine.
J'utilise des gifs pour illustrer à quel point c'est simple. J'espère que vous trouverez les gifs utiles. Juste au cas où vous auriez un problème avec les gifs, j'ai inclus l'ancienne réponse ci-dessous avec des captures d'écran simples.
Instructions:
1) Ajoutez vos boutons ou étiquettes. J'utilise 3 boutons.
2) Ajoutez une contrainte centrale x de chaque bouton à la vue d'ensemble:
3) Ajoutez une contrainte de chaque bouton à la contrainte de mise en page inférieure:
4) Ajustez la contrainte ajoutée au point 3 ci-dessus comme suit:
a) sélectionnez la contrainte, b) supprimez la constante (définie sur 0), c) modifiez le multiplicateur comme suit: prenez le nombre de boutons + 1, et en commençant par le haut, définissez le multiplicateur comme suit: buttonCountPlus1: 1 , puis sur buttonCountPlus1 : 2 , et enfin buttonCountPlus1: 3 . (Si vous êtes intéressé, je vous explique d'où j'ai tiré cette formule dans l'ancienne réponse ci-dessous).
5) Voici une démo en cours d'exécution!
Remarque: Si vos boutons ont des hauteurs plus grandes, vous devrez compenser cela dans la valeur constante car la contrainte vient du bas du bouton.
Ancienne réponse
Malgré les documents d'Apple et l'excellent livre d'Erica Sadun ( disent Auto Layout Demystified ), il est possible d'espacer uniformément les vues sans entretoises. C'est très simple à faire en IB et en code pour n'importe quel nombre d'éléments que vous souhaitez espacer uniformément. Tout ce dont vous avez besoin est une formule mathématique appelée "formule de section". C'est plus simple à faire qu'à expliquer. Je ferai de mon mieux en le démontrant en IB, mais c'est tout aussi facile à faire en code.
Dans l'exemple en question, vous
1) commencez par définir chaque étiquette pour avoir une contrainte centrale. C'est très simple à faire. Contrôlez simplement le glissement de chaque étiquette vers le bas.
2) Maintenez la touche Maj enfoncée, car vous pourriez aussi bien ajouter l'autre contrainte que nous allons utiliser, à savoir le "guide de mise en page de l'espace du bas au bas".
3) Sélectionnez le "guide de mise en page de l'espace inférieur vers le bas" et "centre horizontalement dans le conteneur". Faites cela pour les 3 étiquettes.
Fondamentalement, si nous prenons l'étiquette dont nous voulons déterminer les coordonnées et la divisons par le nombre total d'étiquettes plus 1, alors nous avons un nombre que nous pouvons ajouter à IB pour obtenir l'emplacement dynamique. Je simplifie la formule, mais vous pouvez l'utiliser pour définir l'espacement horizontal ou à la fois vertical et horizontal en même temps. C'est super puissant!
Voici nos multiplicateurs.
Label1 = 1/4 = .25,
Label2 = 2/4 = 0,5,
Label3 = 3/4 = 0,75
(Edit: @Rivera a commenté que vous pouvez simplement utiliser les ratios directement dans le champ multiplicateur, et xCode avec le calcul!)
4) Alors, sélectionnons Label1 et sélectionnons la contrainte inférieure. Comme ça:
5) Sélectionnez le "deuxième élément" dans l'inspecteur d'attributs.
6) Dans le menu déroulant, sélectionnez "Inverser le premier et le deuxième élément".
7) Remettre à zéro la constante et la valeur wC hAny. (Vous pouvez ajouter un décalage ici si vous en avez besoin).
8) Voici la partie critique: dans le champ multiplicateur, ajoutez notre premier multiplicateur 0,25.
9) Pendant que vous y êtes, réglez le premier "Premier élément" sur "CenterY" car nous voulons le centrer sur le centre y de l'étiquette. Voici à quoi tout cela devrait ressembler.
10) Répétez ce processus pour chaque étiquette et branchez le multiplicateur correspondant: 0,5 pour Label2 et 0,75 pour Label3. Voici le produit final dans toutes les orientations avec tous les appareils compacts! Super simple. J'ai étudié de nombreuses solutions impliquant des rames de code et des espaceurs. C'est de loin la meilleure solution que j'ai vue sur la question.
Mise à jour: @kraftydevil ajoute que le guide de disposition inférieur n'apparaît que dans les storyboards, pas dans xibs. Utilisez 'Bottom Space to Container' dans les xibs. Bonne prise!
la source
Solution Interface Builder très rapide:
Pour qu'un nombre illimité de vues soit uniformément espacé dans une superview, donnez simplement à chacune une contrainte "Aligner le centre X sur la superview" pour la disposition horizontale, ou "Aligner le centre Y superview" pour la disposition verticale, et définissez le multiplicateur sur
N:p
( REMARQUE: certains ont eu plus de chance avecp:N
- voir ci-dessous )où
N = total number of views
, etp = position of the view including spaces
La première position est 1, puis un espace, faisant la position suivante 3, donc p devient une série [1,3,5,7,9, ...]. Fonctionne pour n'importe quel nombre de vues.
Donc, si vous avez 3 vues à espacer, cela ressemble à ceci:
EDIT Remarque: Le choix de
N:p
oup:N
dépend de l'ordre des relations de votre contrainte d'alignement. Si "First Item" est Superview.Center, vous pouvez utiliserp:N
, alors que si Superview.Center est "Second Item", vous pouvez utiliserN:p
. En cas de doute, essayez les deux ... :-)la source
Depuis iOS 9, Apple a rendu cela très facile avec le (très attendu)
UIStackView
. Sélectionnez simplement les vues que vous souhaitez contenir dans Interface Builder et choisissez Éditeur -> Incorporer dans -> Vue de la pile. Définissez les contraintes de largeur / hauteur / marge appropriées pour la vue de la pile et assurez-vous de définir la propriété Distribution sur 'Espacement égal':Bien sûr, si vous devez prendre en charge iOS 8 ou une version antérieure, vous devrez choisir l'une des autres options.
la source
J'ai fait des montagnes russes en aimant la mise en page automatique et en la détestant. La clé pour l'aimer semble être d'accepter ce qui suit:
Cela dit, ce que vous tentez n'est pas simple et serait difficile à réaliser dans le générateur d'interface. C'est assez simple à faire en code. Ce code, dans
viewDidLoad
, crée et positionne trois étiquettes comme vous les demandez:Comme je l'ai dit, ce code est très simplifié avec quelques méthodes de catégorie dans
UIView
, mais pour plus de clarté, je l'ai fait longtemps ici.La catégorie est ici pour ceux qui sont intéressés, et elle a une méthode pour espacer uniformément un tableau de vues le long d'un axe particulier.
la source
La plupart de ces solutions dépendent de la présence d'un nombre impair d'articles afin que vous puissiez prendre l'élément du milieu et le centrer. Que se passe-t-il si vous avez un nombre pair d'articles que vous souhaitez tout de même répartir? Voici une solution plus générale. Cette catégorie répartira uniformément n'importe quel nombre d'éléments le long de l'axe vertical ou horizontal.
Exemple d'utilisation pour distribuer verticalement 4 étiquettes dans leur superview:
NSLayoutConstraint + EvenDistribution.h
NSLayoutConstraint + EvenDistribution.m
la source
La manière correcte et la plus simple consiste à utiliser les vues de pile.
la source
Découvrez la bibliothèque open source PureLayout . Il propose quelques méthodes API pour distribuer les vues, y compris des variantes où l'espacement entre chaque vue est fixe (la taille de la vue varie selon les besoins) et où la taille de chaque vue est fixe (l'espacement entre les vues varie selon les besoins). Notez que tout cela est accompli sans l'utilisation de "vues d'espacement".
De NSArray + PureLayout.h :
Comme tout est open source, si vous êtes intéressé de voir comment cela est possible sans les vues d'espacement, jetez un œil à la mise en œuvre. (Cela dépend de la mise à profit des contraintes
constant
etmultiplier
des contraintes.)la source
J'ai un problème similaire et j'ai découvert ce post. Cependant, aucune des réponses actuellement fournies ne résout le problème comme vous le souhaitez. Ils ne font pas l'espacement également, mais distribuent plutôt le centre des étiquettes de manière égale. Il est important de comprendre que ce n'est pas pareil. J'ai construit un petit diagramme pour illustrer cela.
Il y a 3 vues, toutes hautes de 20 points. L'utilisation de l'une des méthodes suggérées répartit également les centres des vues et vous donne la disposition illustrée. Notez que le centre y des vues est espacé de manière égale. Cependant, l'espacement entre la vue d'ensemble et la vue de dessus est de 15 points, tandis que l'espacement entre les vues secondaires n'est que de 5 points. Pour que les vues soient également espacées, elles doivent toutes deux être de 10 pt, c'est-à-dire que toutes les flèches bleues doivent être de 10 pt.
Néanmoins, je n'ai pas encore trouvé de bonne solution générique. Actuellement, ma meilleure idée est d'insérer des "vues d'espacement" entre les sous-vues et de définir des hauteurs des vues d'espacement égales.
la source
J'ai pu résoudre ce problème entièrement dans IB:
Donc, si vous avez trois étiquettes, définissez les multiplicateurs de chacune de ces contraintes sur 0,1666667, 0,5, 0,833333.
la source
J'ai trouvé une méthode parfaite et simple. La disposition automatique ne vous permet pas de redimensionner les espaces de manière égale, mais elle vous permet de redimensionner les vues de manière égale. Mettez simplement des vues invisibles entre vos champs et dites à la mise en page automatique de les garder à la même taille. Ça marche parfaitement!
Une chose à noter cependant; lorsque je réduisais la taille dans le concepteur d'interface, parfois cela devenait confus et laissait une étiquette où il se trouvait, et il y avait un conflit si la taille était modifiée de façon étrange. Sinon, cela a parfaitement fonctionné.
edit: J'ai trouvé que le conflit est devenu un problème. Pour cette raison, j'ai pris l'une des contraintes d'espacement, je l'ai supprimée et je l'ai remplacée par deux contraintes, une supérieure ou égale et une inférieure ou égale. Les deux étaient de la même taille et avaient une priorité beaucoup plus faible que les autres contraintes. Le résultat n'est plus un conflit.
la source
En s'appuyant sur la réponse de Ben Dolman, cela répartit les vues de manière plus égale (avec rembourrage, etc.):
la source
consultez https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html avec une belle description sur la résolution de votre problème.
la source
Avec des étiquettes, cela fonctionne très bien au moins:
@"H:|-15-[first(==second)]-[second(==third)]-[third(==first)]-15-|
Si le premier a la même largeur que le second, le deuxième le troisième et le troisième le premier, alors ils auront tous la même largeur ... Vous pouvez le faire à la fois horizontalement (H) et verticalement (V).
la source
version swift 3
la source
Je sais que cela fait un moment depuis la première réponse, mais je viens de rencontrer le même problème et je veux partager ma solution. Pour les générations à venir ...
J'ai défini mes vues sur viewDidLoad:
Et puis, sur updateViewConstrains, je supprime d'abord toutes les contraintes, puis je crée le dictionnaire des vues, puis je calcule l'espace à utiliser entre les vues. Après cela, j'utilise simplement le Visual Language Format pour définir les contraintes:
La bonne chose à propos de cette méthode est que vous devez faire très peu de mathématiques. Je ne dis pas que c'est la solution parfaite, mais je travaille pour la mise en page que j'essayais de réaliser.
J'espère que ça aide.
la source
Voici une solution qui centrera verticalement n'importe quel nombre de sous-vues, même si elles ont des tailles uniques. Ce que vous voulez faire est de créer un conteneur de niveau intermédiaire, de le centrer dans la vue d'ensemble, puis de placer toutes les sous-vues dans le conteneur et de les organiser les unes par rapport aux autres. Mais surtout, vous devez également les contraindre en haut et en bas du conteneur, afin que le conteneur puisse être correctement dimensionné et centré dans la vue d'ensemble. En calculant la hauteur correcte à partir de ses vues secondaires, le conteneur peut être centré verticalement.
Dans cet exemple,
self
est la vue d'ensemble dans laquelle vous centrez toutes les sous-vues.la source
Je viens de résoudre mon problème en utilisant la fonction multiplicateur. Je ne suis pas sûr que cela fonctionne dans tous les cas, mais pour moi, cela a fonctionné parfaitement. Je suis sur Xcode 6.3 FYI.
J'ai fini par faire:
1) Premièrement, le positionnement de mes boutons sur un écran d'une largeur de 320 pixels était réparti de la façon dont je voulais qu'il apparaisse sur un périphérique de 320 pixels.
2) Ensuite, j'ai ajouté une contrainte d'espace principale à la vue d'ensemble sur tous mes boutons.
3) Ensuite, j'ai modifié les propriétés de l'espace de tête pour que la constante soit 0 et que le multiplicateur soit le décalage x divisé par la largeur de l'écran (par exemple, mon premier bouton était à 8 pixels du bord gauche, j'ai donc réglé mon multiplicateur sur 8/320)
4) Ensuite, l'étape importante ici consiste à modifier le deuxième élément de la relation de contrainte pour qu'il soit superview.Trailing au lieu de superview.leading. Ceci est essentiel parce que superview.Leading est 0 et à la fin dans mon cas est 320, donc 8/320 est 8 px sur un périphérique 320px, puis lorsque la largeur de la superview passe à 640 ou autre, les vues se déplacent toutes dans un rapport par rapport à la largeur de la taille de l'écran 320px. Les mathématiques ici sont beaucoup plus simples à comprendre.
la source
De nombreuses réponses ne sont pas correctes, mais obtiennent de nombreux décomptes. Ici, je viens d'écrire une solution par programme, les trois vues sont alignées horizontalement, sans utiliser de vues d'espacement , mais cela ne fonctionne que lorsque les largeurs des étiquettes sont connues lorsqu'elles sont utilisées dans le storyboard .
la source
Voici encore une autre réponse. Je répondais à une question similaire et j'ai vu le lien renvoyé à cette question. Je n'ai pas vu de réponse similaire à la mienne. J'ai donc pensé à l'écrire ici.
Et encore une fois, cela peut être fait assez facilement avec iOS9 UIStackViews.
Notez que c'est exactement la même approche que ci-dessus. Il ajoute quatre vues de conteneur qui sont remplies de manière égale et une vue est ajoutée à chaque vue de pile qui est alignée au centre. Mais, cette version de UIStackView réduit le code et semble agréable.
la source
Une autre approche pourrait consister à faire en sorte que les étiquettes supérieure et inférieure aient des contraintes par rapport à la vue supérieure et inférieure, respectivement, et que la vue du milieu ait des contraintes supérieure et inférieure par rapport à la première et à la troisième vue, respectivement.
Notez que vous avez plus de contrôle sur les contraintes qu'il n'y paraît en faisant glisser les vues les unes vers les autres jusqu'à ce que des lignes pointillées de guidage apparaissent - elles indiquent les contraintes entre les deux objets qui seront formées plutôt qu'entre l'objet et la vue d'ensemble.
Dans ce cas, vous souhaiterez alors modifier les contraintes pour qu'elles soient "supérieures ou égales à" la valeur souhaitée, au lieu de "égales à" pour leur permettre de se redimensionner. Je ne sais pas si cela fera exactement ce que vous voulez.
la source
Un moyen très simple de résoudre ce problème dans InterfaceBuilder:
Définissez l'étiquette centrée (label2) sur "Centre horizontal dans le conteneur" et "Centre vertical dans le conteneur"
Sélectionnez l'étiquette centrée et l'étiquette supérieure (étiquette1 + étiquette2) et ajoutez DEUX contraintes pour l'espacement vertical. Un avec un espacement supérieur ou égal à min. Un avec moins que ou égal à l'espacement maximum.
De même pour l'étiquette centrée et l'étiquette inférieure (étiquette2 + étiquette3).
De plus, vous pouvez également ajouter deux contraintes à label1 - Espace supérieur vers SuperView et deux contraintes à label2 - Espace inférieur vers SuperView.
Le résultat sera que les 4 espacements changeront leurs tailles également.
la source
J'ai créé une fonction qui pourrait aider. Cet exemple d'utilisation:
provoquera cette distribution verticale (désolé de ne pas avoir la réputation d'intégrer des images). Et si vous modifiez l'axe et certaines valeurs de marge:
Vous obtiendrez cette distribution horizontale .
Je suis novice dans iOS mais voilà!
EvenDistribution.h
EvenDistribution.m
la source
Oui, vous pouvez le faire uniquement dans le générateur d'interface et sans écrire de code - la seule mise en garde est que vous redimensionnez l'étiquette au lieu de distribuer des espaces. Dans ce cas, alignez les X et Y de l'étiquette 2 sur la vue d'ensemble afin qu'elle soit fixée au centre. Ensuite, définissez l'espace vertical de l'étiquette 1 sur la vue d'ensemble et pour étiqueter 2 sur la norme, répétez pour l'étiquette 3. Après avoir défini l'étiquette 2, la façon la plus simple de définir les étiquettes 1 et 3 est de les redimensionner jusqu'à ce qu'elles s'enclenchent.
Voici l'affichage horizontal, notez que l'espace vertical entre les étiquettes 1 et 2 est réglé sur standard:
Et voici la version portrait:
Je me rends compte qu'ils ne sont pas absolument à 100% également espacés entre les lignes de base en raison de la différence entre l'espace standard entre les étiquettes et l'espace standard à la vue d'ensemble. Si cela vous dérange, définissez la taille sur 0 au lieu de standard
la source
J'ai défini une valeur de largeur juste pour le premier élément (> = une largeur) et une distance minimale entre chaque élément (> = une distance). Ensuite, j'utilise Ctrl pour faire glisser le deuxième, le troisième ... élément sur le premier pour enchaîner les dépendances entre les éléments.
la source
Tard dans la fête mais j'ai une solution de travail pour créer un menu horizontalement avec un espacement. Cela peut être facilement fait en utilisant
==
dans NSLayoutConstraintla source
Android a une méthode de chaînage des vues dans son système de mise en page basé sur des contraintes que je voulais imiter. Les recherches m'ont amené ici mais aucune des réponses n'a tout à fait fonctionné. Je ne voulais pas utiliser StackViews car ils ont tendance à me causer plus de chagrin qu'ils n'en économisent d'avance. J'ai fini par créer une solution qui utilisait des UILayoutGuides placés entre les vues. Le contrôle de leur largeur permet différents types de distributions, des styles de chaîne dans le langage Android. La fonction accepte une ancre de début et de fin au lieu d'une vue parent. Cela permet à la chaîne d'être placée entre deux vues arbitraires plutôt que distribuée à l'intérieur de la vue parent. Il utilise
UILayoutGuide
ce qui n'est disponible que dans iOS 9+ mais cela ne devrait plus être un problème.la source
Je voulais aligner horizontalement 5 images, donc j'ai fini par suivre la réponse de Mete avec une petite différence.
La première image sera centrée horizontalement dans un conteneur égal à 0 et un multiplicateur de 1: 5:
La deuxième image sera centrée horizontalement dans un conteneur égal à 0 et un multiplicateur de 3: 5:
Et comme ça pour le reste des images. Par exemple, la cinquième (et dernière) image sera centrée horizontalement dans un conteneur égal à 0 et un multiplicateur de 9: 5:
Comme Mete l'a expliqué, l'ordre passe à 1, 3, 5, 7, 9, etc. Les positions suivent la même logique: la première position est 1, puis l'espace, puis la position suivante 3, et ainsi de suite.
la source
Pourquoi ne créez-vous pas simplement une table
isScrollEnabled = false
la source