342 votes

Émule le comportement d’aspect-ajustement à l’aide des contraintes de mise en forme automatique dans Xcode 6

Je veux utiliser la mise en forme automatique de la taille et de la mise en page a afficher dans une manière qui rappelle UIImageView l'aspect d'ajustement du mode de contenu.

J'ai une sous-vue à l'intérieur d'un conteneur de vue dans Interface Builder. La sous-vue a autant de rapport d'aspect que je tiens à respecter. Le conteneur de vue de la taille est inconnue jusqu'à ce que l'exécution.

Si le conteneur de vue de l'aspect ratio est plus large que la sous-vue, alors je veux la sous-vue de la hauteur est égale à la vue parente de la hauteur.

Si le conteneur de vue de l'aspect ratio est plus grand que la sous-vue, alors je veux la sous-vue de la largeur de l'égalité de la vue parent de largeur.

Dans les deux cas, je souhaite la sous-vue pour être centré horizontalement et verticalement à l'intérieur du conteneur de vue.

Est-il un moyen pour y parvenir avec mise en page automatique des contraintes dans Xcode 6 ou dans la version précédente? Idéalement utilisant une Interface Builder, mais si non c'est peut-être possible de définir des contraintes de la programmation.

1057voto

rob mayoff Points 124153

Vous n'êtes pas de décrire à l'échelle d'ajustement; vous ne faites que décrire l'aspect de l'ajustement. (J'ai édité votre question à cet égard.) La sous-vue devient aussi grande que possible, tout en maintenant son ratio d'aspect et de montage entièrement à l'intérieur de son parent.

De toute façon, vous pouvez faire cela avec mise en page automatique. Vous pouvez le faire entièrement à l'IB de Xcode 5.1. Nous allons commencer avec quelques vues:

some views

La lumière verte de la vue a un rapport d'aspect de 4:1. Le vert foncé de la vue a un aspect ratio de 1:4. Je vais définir des contraintes, de sorte que le bleu de la vue remplit la moitié supérieure de l'écran, la rose de la vue remplit la moitié inférieure de l'écran, et chaque affichage vert se développe autant que possible, tout en maintenant son ratio d'aspect et de montage dans son conteneur.

Tout d'abord, je vais créer des contraintes sur les quatre côtés de la bleue de vue. Je vais l'épingler à son plus proche voisin sur chaque bord, avec une distance de 0. J'ai assurez-vous de désactiver les marges:

blue constraints

Notez que je n'est pas de mise à jour de l'image encore. Je le trouve plus facile de laisser de l'espace entre les points de vue lors de la configuration de contraintes, et juste définir les constantes de 0 (ou autre) à la main.

Ensuite, j'ai la broche de la gauche, en bas et à droite de la rose vue de son plus proche voisin. Je n'ai pas besoin de configurer un bord supérieur de la contrainte parce que son bord supérieur est déjà limitée à la bordure inférieure de la bleue de vue.

pink constraints

J'ai également besoin d'un accès égal aux hauteurs de contrainte entre le rose et le bleu points de vue. Ce sera à chacun de remplir la moitié de l'écran:

enter image description here

Si je dis Xcode pour mettre à jour toutes les images maintenant, je reçois ceci:

containers laid out

Donc, les contraintes, j'ai mis en place jusqu'à présent sont corrects. - Je l'annuler et commencer les travaux sur la lumière verte de la vue.

Aspect-montage de la lumière verte de vue nécessite cinq contraintes:

  • Un nécessaire de priorité ratio d'aspect de la contrainte sur la lumière verte de la vue. Vous pouvez créer cette contrainte dans un xib ou storyboard avec Xcode 5.1 ou une version ultérieure.
  • Un nécessaire de priorité contrainte de limitation de la largeur de la lumière verte de vue à être inférieure ou égale à la largeur de son conteneur.
  • Une haute priorité contrainte de réglage de la largeur de la lumière verte de vue à être égale à la largeur de son conteneur.
  • Un nécessaire de priorité contrainte limitant la hauteur de la lumière verte de vue à être inférieure ou égale à la hauteur de son conteneur.
  • Une haute priorité contrainte de réglage de la hauteur de la lumière verte de vue à être égale à la hauteur de son conteneur.

Considérons les deux la largeur de contraintes. La moins-que-ou-égal contrainte, par lui-même, n'est pas suffisante pour déterminer la largeur de la lumière verte de la vue; de nombreuses largeurs de s'adapter à la contrainte. Puisqu'il y a ambiguïté, de la mise en page automatique va essayer de choisir une solution qui minimise l'erreur dans l'autre (haute priorité, mais pas nécessaire) contrainte. En minimisant l'erreur signifie faire de la largeur d'aussi près que possible du conteneur largeur, sans violer la moins-que-ou-égal contrainte.

La même chose arrive avec la hauteur de la contrainte. Et depuis le rapport d'aspect de contrainte est également nécessaire, il peut seulement augmenter la taille de la sous-vue le long d'un axe (à moins que le conteneur arrive à avoir le même format que la sous-vue).

J'ai tout d'abord créer le ratio d'aspect de la contrainte:

top aspect

Puis-je créer l'égalité de la largeur et de la hauteur des contraintes avec le conteneur:

top equal size

J'ai besoin de modifier ces contraintes être inférieur ou égal contraintes:

top less than or equal size

Ensuite, j'ai besoin de créer une autre série de la même largeur et la hauteur des contraintes avec le conteneur:

top equal size again

Et j'ai besoin de faire ces nouvelles contraintes moins de priorité requis:

top equal not required

Enfin, vous avez demandé la sous-vue d'être centré dans son conteneur, donc je vais mettre en place ces contraintes:

top centered

Maintenant, pour tester, je vais sélectionner la vue-contrôleur et demander Xcode pour mettre à jour tous les cadres. C'est ce que j'obtiens:

incorrect top layout

Oups! La sous-vue a élargi afin de remplir complètement son conteneur. Si j'ai choisi, et je le vois qu'en fait il est maintenu ses proportions, mais elle fait un aspectde remplissage au lieu d'un aspect-fit.

Le problème est que sur un moins-que-ou-égal contrainte, il importe de vue qui est à chaque extrémité de la contrainte, et Xcode a mis en place la contrainte à l'opposé de mon attente. J'ai pu sélectionner chacune des deux contraintes et à l'inverse de ses première et deuxième éléments. Au lieu de cela, je vais sélectionnez la sous-vue et de modifier les contraintes être supérieur ou égal:

fix top constraints

Xcode mises à jour de la mise en page:

correct top layout

Maintenant, je fais tout de même des choses pour le vert foncé de la vue sur le fond. J'ai besoin de s'assurer que son aspect ratio est de 1:4 (Xcode redimensionnée dans une manière bizarre puisqu'il n'a pas de contraintes). Je ne vais pas vous montrer les étapes à nouveau, car ils sont les mêmes. Voici le résultat:

correct top and bottom layout

Maintenant, je peux le faire tourner sur l'iPhone 4S simulateur, qui est différente de la taille de l'écran que IB utilisé, et le test de rotation:

iphone 4s test

Et je peux tester dans l'iPhone 6 simulateur:

iphone 6 test

J'ai téléchargé la version définitive de mon storyboard pour ce gist pour votre commodité.

24voto

Johannes Fahrenkrug Points 12795

Rob, votre réponse est génial! Je sais aussi que cette question est précisément à propos de la réalisation de ce par l'utilisation de l'auto-layout. Cependant, tout comme une référence, j'aimerais vous montrer comment cela peut être fait dans le code. Vous définissez le haut et le bas de vues (bleu et rose) tout comme Rob a montré. Ensuite, vous créez une coutume AspectFitView:

AspectFitView.h:

#import <UIKit/UIKit.h>

@interface AspectFitView : UIView

@property (nonatomic, strong) UIView *childView;

@end

AspectFitView.m:

#import "AspectFitView.h"

@implementation AspectFitView

- (void)setChildView:(UIView *)childView
{
    if (_childView) {
        [_childView removeFromSuperview];
    }

    _childView = childView;

    [self addSubview:childView];
    [self setNeedsLayout];
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    if (_childView) {
        CGSize childSize = _childView.frame.size;
        CGSize parentSize = self.frame.size;
        CGFloat aspectRatioForHeight = childSize.width / childSize.height;
        CGFloat aspectRatioForWidth = childSize.height / childSize.width;

        if ((parentSize.height * aspectRatioForHeight) > parentSize.height) {
            // whole height, adjust width
            CGFloat width = parentSize.width * aspectRatioForWidth;
            _childView.frame = CGRectMake((parentSize.width - width) / 2.0, 0, width, parentSize.height);
        } else {
            // whole width, adjust height
            CGFloat height = parentSize.height * aspectRatioForHeight;
            _childView.frame = CGRectMake(0, (parentSize.height - height) / 2.0, parentSize.width, height);
        }
    }
}

@end

Ensuite, vous modifiez la classe du bleu et rose vues dans le storyboard pour être AspectFitViews. Enfin, vous définissez deux points de vente à votre viewcontroller topAspectFitView et bottomAspectFitView , et à définir leurs childViews dans viewDidLoad:

- (void)viewDidLoad {
    [super viewDidLoad];

    UIView *top = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 100)];
    top.backgroundColor = [UIColor lightGrayColor];

    UIView *bottom = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 500)];
    bottom.backgroundColor = [UIColor greenColor];

    _topAspectFitView.childView = top;
    _bottomAspectFitView.childView = bottom;
}

Il n'est donc pas difficile de le faire dans le code et qu'il est très adaptable et fonctionne avec la variable de la taille de vues et de différents rapports d'aspect.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X