84 votes

Créer des contraintes de mise en page de manière programmatique

Je sais que beaucoup de gens ont déjà posé des tonnes de questions à ce sujet, mais même avec les réponses, je n'arrive pas à le faire fonctionner.

Lorsque je traite des contraintes sur le storyboard, c'est facile, mais dans le code, j'ai du mal. J'essaie, par exemple, d'avoir une vue qui reste sur le côté droit et qui a la hauteur de l'écran selon l'orientation de l'écran. Voici mon code :

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

Il ne satisfait pas à certaines contraintes. Je ne vois pas ce qui ne va pas. Par ailleurs, pourquoi ne puis-je pas utiliser une propriété comme self.myView au lieu d'une variable locale comme myView ?

106voto

larsacus Points 4024

Lorsque l'on utilise la mise en page automatique dans le code, le fait de définir le cadre ne fait rien. Ainsi, le fait que vous ayez spécifié une largeur de 200 sur la vue ci-dessus ne signifie rien lorsque vous lui imposez des contraintes. Pour que l'ensemble des contraintes d'une vue soit sans ambiguïté, il faut quatre éléments : une position x, une position y, une largeur et une hauteur pour tout état donné.

Actuellement, dans le code ci-dessus, vous n'en avez que deux (height, relative à la vue supérieure, et y-position, relative à la vue supérieure). En plus de cela, vous avez deux contraintes obligatoires qui pourraient entrer en conflit selon la façon dont les contraintes de la vue principale sont configurées. Si si la vue supérieure devait avoir une contrainte obligatoire spécifiant que sa hauteur doit être inférieure à 748, vous obtiendriez une exception de type "contraintes insatisfaisantes".

Le fait que vous ayez défini la largeur de la vue avant de définir les contraintes ne signifie rien. Il ne tiendra même pas compte de l'ancien cadre et calculera un nouveau cadre sur la base de toutes les contraintes qu'il a spécifiées pour ces vues. Lorsque j'utilise la mise en page automatique dans le code, je crée généralement une nouvelle vue à l'aide de la commande initWithFrame:CGRectZero ou simplement init .

Pour créer l'ensemble de contraintes requis pour la mise en page que vous avez décrite verbalement dans votre question, vous devez ajouter des contraintes horizontales pour délimiter la largeur et la position x afin d'obtenir une mise en page entièrement spécifiée :

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

La description verbale de cette disposition se lit comme suit, en commençant par la contrainte verticale :

myView remplira la hauteur de sa vue supérieure avec un padding supérieur et inférieur égal à l'espace standard. La vue supérieure de myView a une hauteur minimale de 748pts. de 748pts. La largeur de myView est de 200pts et a un padding droit égal à l'espace standard contre sa super-vue. l'espace standard contre sa vue supérieure.

Si vous souhaitez simplement que la vue remplisse toute la hauteur de la vue supérieure sans la contraindre, il vous suffit d'omettre l'élément (>=748) dans le texte du format visuel. Si vous pensez que le (>=748) est nécessaire pour lui donner une hauteur - ce qui n'est pas le cas ici : le fait d'épingler la vue aux bords de la vue supérieure à l'aide de la barre ( | ) ou barre avec espace ( |- , -| ), vous donnez à votre vue une position y (épinglant la vue sur un seul bord), et une position y avec une hauteur (épinglant la vue sur les deux bords), satisfaisant ainsi votre ensemble de contraintes pour la vue.

En ce qui concerne votre deuxième question :

Utilisation de NSDictionaryOfVariableBindings(self.myView) (si vous aviez une propriété configurée pour myView) et l'introduire dans votre VFL pour utiliser self.myView dans votre texte VFL, vous obtiendrez probablement une exception lorsque autolayout essaiera d'analyser votre texte VFL. Cela est dû à la notation par points des clés de dictionnaire et au fait que le système essaie d'utiliser la notation par points. valueForKeyPath: . Voir ici pour une question et une réponse similaires .

61voto

BriOnH Points 341

Bonjour, j'ai beaucoup utilisé cette page pour les contraintes et les "comment faire". Il m'a fallu une éternité pour arriver à réaliser ce dont j'avais besoin :

myView.translatesAutoresizingMaskIntoConstraints = NO;

pour que cet exemple fonctionne. Merci à Userxxx, Rob M. et surtout larsacus pour les explications et le code ici, ils ont été inestimables.

Voici le code complet pour faire fonctionner les exemples ci-dessus :

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

5voto

iDev Points 16260

En ce qui concerne votre deuxième question sur les propriétés, vous pouvez utiliser self.myView seulement si vous l'avez déclaré comme une propriété dans la classe. Depuis myView est une variable locale, vous ne pouvez pas l'utiliser de cette façon. Pour plus de détails à ce sujet, je vous recommande de parcourir la documentation d'apple sur Propriétés déclarées ,

5voto

Megarushing Points 377

pourquoi ne puis-je pas utiliser une propriété comme self.myView au lieu d'une variable locale comme myView ?

essayer en utilisant : NSDictionaryOfVariableBindings(_view) au lieu de self.view

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