web-dev-qa-db-fra.com

Mise en page automatique (contraintes) Centrer deux vues côte à côte dans une vue parent

J'essaie de comprendre comment faire cela avec la mise en page automatique (iOS6) et les contraintes.

Fondamentalement, j'ai ma grande vue divisée en deux sections sur le bas. À l'intérieur de ces sections (actuellement des sous-vues), j'ai une vue d'image et une étiquette. Je veux centrer ceux des deux côtés, avec un texte de longueur variable.

Ma tête est principalement tournée vers la mise en page automatique, mais je ne suis pas sûre de la meilleure approche à cet égard. Je suis enclin à penser que ce n'est pas possible dans IB, mais est dans le code.

Je vais continuer à essayer de comprendre cela, mais en attendant voici l'exemple que j'essaie de créer.

enter image description here

65
Bob Spryn

Est-ce ce que vous recherchez?

short labellong label

Je l'ai fait en ajoutant une vue (nommée viewCenteredInLeftSection) dans votre leftSection, puis en ajoutant l'image d'horloge et le libellé en tant que sous-vues avec les contraintes suivantes:

  • Faites en sorte que viewCenteredInLeftSection's CenterX et CenterY soient égaux à ceux de sa superview (leftSection).
  • Faites en sorte que les bords supérieur, inférieur et avant de clockImage soient égaux à ceux de sa superview (viewCenteredInLeftSection).
  • Faites en sorte que le bord de fuite de label soit égal à celui de son superview (viewCenteredInLeftSection).
  • Définissez le bord de fuite de clockImage à la distance standard du bord d'attaque de label.

viewCenteredInLeftSection

Je ne parviens pas à redimensionner UIViews iOS dans Interface Builder. J'ai donc créé mon exemple pour OS X et je pouvais le faire entièrement dans Interface Builder. Si vous rencontrez des difficultés pour créer les contraintes ci-dessus dans Interface Builder, faites-le moi savoir et je posterai le code qui les créera.

2014-08-26 Modifier

Luda , voici les menus Pin et Align de Xcode 5, également disponibles dans la barre de menus de Xcode:

Align menuPin menu

Voici à quoi mon exemple ressemble dans Interface Builder. La vue bleue est la "vue parente" de la question d'origine, la vue donnée dans laquelle l'image et l'étiquette doivent être centrées.

J'ai ajouté la vue verte (que j'ai nommée viewCenteredInLeftSection) en tant que sous-vue de "vue parent". Ensuite, je l'ai surligné et utilisé les menus Aligner "Centre horizontal dans le conteneur" et "Centre vertical dans le conteneur" pour créer des contraintes permettant de définir sa position.

J'ai ajouté l'image d'horloge en tant que sous-vue de viewCenteredInLeftSection, avec des contraintes définissant sa largeur et sa hauteur. J'ai mis en surbrillance l'image d'horloge et viewCenteredInLeftSection, puis j'ai appliqué des contraintes en utilisant Aligner> Tranches principales, Aligner> Tranches supérieures et Aligner> Tranches inférieures.

J'ai ajouté l'étiquette en tant que sous-vue de viewCenteredInLeftSection, en la positionnant comme la distance spatiale Aqua standard de l'image de l'horloge. J'ai mis en surbrillance le libellé et viewCenteredInLeftSection, puis j'ai appliqué des contraintes à l'aide de l'option Aligner> Arêtes inférieures.

C'était beaucoup plus facile à créer avec Interface Builder de Xcode 5 par rapport à celui de Xcode 4.

Interface Builder

59
John Sauer

J'ai trouvé un moyen sans ajouter une autre vue:

 [aView addConstraint:[NSLayoutConstraint constraintWithItem:viewOnLeft attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationLessThanOrEqual toItem:aView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
 [aView addConstraint:[NSLayoutConstraint constraintWithItem:viewOnRight attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationLessThanOrEqual toItem:aView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];

Vous pouvez également modifier les constantes pour créer un espace entre les vues.

  • constante de contrainte de vue gauche: -X
  • constante de contrainte vue droite: +X

centering subviews

29
Lucien

Cela m'a pris un peu de temps, mais j'ai trouvé une solution assez solide. J'ai imaginé la même solution que John Sauer, mais je ne voulais pas ajouter une autre vue pour intégrer ces éléments.

La réponse nécessite trois étapes.

1) La largeur de ma sous-vue contenant les deux autres, que je nommerai leftInfoSection, doit être déterminée par son contenu. Cela supprime le besoin d'avoir des contraintes de gauche et de droite dans un aperçu (ou une autre vue) pour déterminer sa largeur. C’est une vraie clé avec beaucoup de choses qui permettent aux enfants de définir les largeurs.

enter image description here

2) Je devais toujours avoir une contrainte de premier plan dans IB pour que sa présentation soit valide. (Il fallait savoir où placer la leftInfoSection horizontalement). Câblez cette contrainte dans votre code afin de pouvoir la supprimer. En plus de cela, j'avais une contrainte de fuite GTE le diviseur vertical + 3.

3) La dernière clé consiste à réfléchir aux informations avec lesquelles vous devez travailler (dans le code, IB étant limité). J'ai réalisé que je connaissais le centre du diviseur horizontal au-dessus de ma section et que le centre de ma leftInfoSection serait le centre de la barre horizontale moins le quart de la largeur de la barre horizontale. Voici le code final pour les côtés gauche et droit:

// remove the unwanted constraint to the right side of the thumbnail
[self.questionBox removeConstraint:self.leftInfoViewLeadingConstraint];
// calculate the center of the leftInfoView
CGFloat left = self.horizontalDividerImageView.frame.size.width/4 * -1;
// constrain the center of the leftInfoView to the horizontal bar center minus a quarter of it to center things
[self.questionBox addConstraint:[NSLayoutConstraint constraintWithItem:self.leftInfoView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.horizontalDividerImageView attribute:NSLayoutAttributeCenterX multiplier:1 constant:left]];

// remove the unwanted constraint to the right side of the questionBox
[self.questionBox removeConstraint:self.rightInfoViewTrailingConstraint];
// calculate the center of the rightInfoView
CGFloat right = left * -1;
// constrain the center of the rightInfoView to the horizontal bar center plus a quarter of it to center things
[self.questionBox addConstraint:[NSLayoutConstraint constraintWithItem:self.rightInfoView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.horizontalDividerImageView attribute:NSLayoutAttributeCenterX multiplier:1 constant:right]];

Résultat: Final result

De plus, IB peut être très ennuyant avec la façon dont il met automatiquement à jour les contraintes. Lorsque j'essayais de définir 0 sur les contraintes de début et de fin sur les sous-vues, cela continuait de déconnecter l'une ou l'autre et de créer une contrainte sur la vue d'ensemble pour définir la largeur. L'astuce consistait à laisser temporairement cette contrainte indésirable en place, mais à réduire sa priorité à 999. Ensuite, j'ai pu créer des contraintes mais une sous-vue pour définir la largeur.

16
Bob Spryn

Une solution à cela est envisagée dans les conférences de l’université de stanford sur ios 7.Il fonctionne à merveille. (Ici, sdfssfg ... chose est label1 et efsdfg .... chose est label2)

enter image description here

14
Vinayak Parmar

Cela fonctionne plutôt bien mais nécessite 2 spacer UIView's:

UIView *spacer1 = [[UIView alloc] init];
spacer1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:spacer1];

UIView *spacer2 = [[UIView alloc] init];
spacer2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:spacer2];

NSDictionary *views = NSDictionaryOfVariableBindings(spacer1, spacer2, imageView, label);

[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[spacer1(>=0)][imageView]-4-[label][spacer2(==spacer1)]|" options:0 metrics:nil views:views];

for (int i = 0; i < constraintsArray.count; i++) {

    [self.view addConstraint:constraintsArray[i]];
}
11
Christian

Après iOS 9, une autre option consiste à utiliser Stack Views

5
alcamla

Vous voudrez peut-être renvoyer ceci 

Marquage en pourcentage

En gros, il dit d’abord d’être avec une marge incorrecte, puis de le corriger par rapport à la vue parent. 

Travailler avec mon cas. 

0
Amitg2k12

Il y a plusieurs moyens de le faire. En termes de base, voici comment centrer des éléments, en supposant que tous vos éléments ont des tailles limitées et ne vont pas sur grandissent .

  1. Placez 2 entretoises de chaque côté de vos objets. Ancrer les entretoises aux bords parents. Ancrez vos premier et dernier articles aux ancres. Enfin, attribuez une entretoise à la largeur de l’autre. Vous n'avez pas besoin de définir explicitement une taille d'espacement, car elle sera résolue .

    • spacer1 -> left = parent: left width = spacer2: width
    • spacer2 -> right = parent: right
    • yourFirstItem -> left = spacer1: right
    • yourLastItem -> right = spacer2: left
  2. Si les entretoises ne vous conviennent pas et que vous avez un nombre impair d'éléments, centrez celle du milieu sur le centre du parent. Assurez-vous également que les premier et dernier éléments ne sont pas ancrés aux bords parents.

    • yourMiddleItem = centerX = parent: centerX
    • otherItems-> yourMiddleItem <-otherItems
  3. Si les espaceurs ne vous conviennent pas et que vous avez un nombre pair d'éléments, centrez les bords des 2 éléments intérieurs sur le centre du parent. Assurez-vous également que les premier et dernier éléments ne sont pas ancrés aux bords parents.

    • leftMiddleItem -> right = parent: centerX
    • rightMiddleItem -> left = parent: centerX
    • otherItems-> leftMiddleItem rightMiddleItem <-otherItems
  4. Vous pouvez également centrer un espace réservé invisible au centre et y ancrer, mais vous devrez tout de même prendre en compte un nombre impair/pair d'éléments contraignants. Je ne recommande donc pas cette approche.

0
Steven Spungin