Création de contraintes de mise en page par programmation

84

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

Quand je suis confronté à des contraintes sur le storyboard, c'est facile mais dans le code j'ai du mal. J'essaye, par exemple, d'avoir une vue qui reste sur le côté droit et a la hauteur de l'écran en fonction de 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)]];

Cela ne satisfait pas certaines contraintes. Je ne vois pas ce qui ne va pas. Aussi, pourquoi ne puis-je pas utiliser une propriété comme self.myViewau lieu d'une variable locale comme myView?

pierre23
la source
Qu'est-ce que vivi dans le code ci-dessus?
iDev
14
Veuillez changer le titre en "iOS" au lieu de "IOS" - Ce dernier fait référence au système d'exploitation de commutateur / routeur de Cisco. M'a perturbé. Merci.
armani
1
Plusieurs questions à ce sujet: (1) Quelle erreur obtenez-vous quand il "ne satisfait pas certaines contraintes"? (2) Traduisez-vous la redimensionnement automatique en contraintes myView? (3) Qu'est-ce que vivi(comme l'ACB l'a demandé)? (4) Avez-vous une propriété myViewdéclarée sur self?
Tim
1
ih Tim, eh bien désolé le vivi, j'ai tapoté trop vite ... c'est myView. Qu'entendez-vous par traduction? Tout ce que je fais, c'est sur le code ci-dessus. A propos de la propriété, j'ai d'autres vues qui sont déclarées comme propriété mais quand j'implémente le même code sur ces propriétés, cela plante ... le message "error" est vraiment gros, je ne peux pas le coller ici
pierre23
Pour supprimer temporairement les contraintes d'une vue particulière, procédez comme suit
Sam B

Réponses:

106

Lors de l'utilisation de la disposition automatique dans le code, la définition du cadre ne fait rien. Donc, le fait que vous ayez spécifié une largeur de 200 sur la vue ci-dessus ne veut rien dire lorsque vous définissez des contraintes dessus. Pour que l'ensemble de contraintes d'une vue soit sans ambiguïté, il lui faut quatre choses: une position x, une position y, une largeur et une hauteur pour un état donné.

Actuellement dans le code ci-dessus, vous n'en avez que deux (hauteur, par rapport à la vue supervisée, et position y, par rapport à la vue supervisée). En plus de cela, vous avez deux contraintes requises qui peuvent entrer en conflit en fonction de la configuration des contraintes de la vue supervisée de la vue. Si le superview devait avoir une contrainte obligatoire qui spécifie que sa hauteur est une valeur inférieure à 748, vous obtiendrez une exception "contraintes non satisfaites".

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

Pour créer le jeu 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 de donner 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 supervision avec un rembourrage haut et bas égal à l'espace standard. Le superview de myView a une hauteur minimale de 748 points. La largeur de myView est de 200 points et a un remplissage à droite égal à l'espace standard par rapport à sa vue de dessus.

Si vous souhaitez simplement que la vue remplisse toute la hauteur de la vue supervisée sans contraindre la hauteur de la vue supervisée, vous omettez simplement le (>=748)paramètre dans le texte au format visuel. Si vous pensez que le (>=748)paramètre est nécessaire pour lui donner une hauteur - vous ne le faites pas dans ce cas: épingler la vue sur les bords de la vue supervisée en utilisant la syntaxe bar ( |) ou bar avec espace ( |-, -|), vous donnez à votre vue un y -position (épinglant la vue sur un seul bord), et une position y avec la hauteur (épinglant la vue sur les deux bords), satisfaisant ainsi votre jeu de contraintes pour la vue.

En ce qui concerne votre deuxième question:

En utilisant NSDictionaryOfVariableBindings(self.myView)(si vous aviez une configuration de propriété pour myView) et en l'introduisant dans votre VFL à utiliser self.myViewdans votre texte VFL, vous obtiendrez probablement une exception lorsque la mise en page automatique essaiera d'analyser votre texte VFL. Cela a à voir avec la notation par points dans les clés du dictionnaire et le système essayant d'utiliser valueForKeyPath:. Voir ici pour une question et une réponse similaires .

larsaque
la source
N'oubliez pas que certains objets comme UILabel ont une taille intrinsèque et vous n'avez pas à définir la largeur ou la hauteur de cet objet, seulement sa position. Cependant, si vous définissez la hauteur ou la largeur, je pense que cela supprime les deux et vous devez ensuite fournir les deux.
Nick Turner
Même si cette réponse n'a pas répondu à ma question, elle m'a aidé à réaliser quelque chose. Merci d'être! :)
Matej
1
La seule introduction de mise en page automatique concise et lisible sur Internet à ce jour.
Joey Carson
plz aidez-moi ma question est la suivante ... je ne sais pas comment utiliser les contraintes par programmation stackoverflow.com/questions/36326288
61

Salut, j'utilise beaucoup cette page pour les contraintes et le "comment faire". Il m'a fallu une éternité pour arriver au point de réaliser que j'avais besoin:

myView.translatesAutoresizingMaskIntoConstraints = NO;

pour que cet exemple fonctionne. Merci Userxxx, Rob M. et surtout larsacus pour l'explication et le code ici, cela a été inestimable.

Voici le code complet pour obtenir les exemples ci-dessus à exécuter:

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)]];
BriOnH
la source
11

Version Swift

Mis à jour pour Swift 3

Cet exemple montre deux méthodes pour ajouter par programme les contraintes suivantes de la même manière que si vous le faisiez dans Interface Builder:

Largeur et hauteur

entrez la description de l'image ici

Centrer dans le conteneur

entrez la description de l'image ici

Code de la chaudière

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

Méthode 1: Style d'ancrage

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

Méthode 2: Style NSLayoutConstraint

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

Remarques

  • Le style d'ancrage est la méthode préférée par rapport au NSLayoutConstraintstyle, mais il n'est disponible qu'à partir d'iOS 9, donc si vous prenez en charge iOS 8, vous devez toujours utiliser NSLayoutConstraintStyle.
  • Voir aussi la documentation Création de contraintes par programme .
  • Consultez cette réponse pour un exemple similaire d'ajout d'une contrainte d'épinglage.
Suragch
la source
5

Concernant votre deuxième question sur les propriétés, vous ne pouvez l'utiliser self.myViewque si vous l'avez déclarée comme propriété en classe. Puisqu'il myViews'agit d'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 Apple sur les propriétés déclarées ,

iDev
la source
5

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

essayez d'utiliser:

NSDictionaryOfVariableBindings(_view)

au lieu de self.view

Megarushing
la source
Cela fait que mon application plante, elle donne un message: "Impossible d'analyser le format de contrainte: polylineImageView n'est pas une clé dans le dictionnaire de vues.
Tai Le
4

Veuillez également noter qu'à partir d'iOS9, nous pouvons définir des contraintes par programmation «plus concises et plus faciles à lire» en utilisant des sous-classes de la nouvelle classe d'assistance NSLayoutAnchor .

Un exemple de la doc:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
andreacipriani
la source