web-dev-qa-db-fra.com

Puis-je utiliser setFrame et autolayout sur la même vue?

Je veux ajouter un remplissage à tous mes boutons, j'ai donc sous-classé UIButton, et entre autres changements, je voulais ajouter un remplissage fixe en utilisant la méthode setFrame. Tout fonctionnait, sauf pour setFrame. J'ai vérifié autour de moi, et j'ai découvert que si je décochez "en utilisant AutoLayout" sur cette vue, alors je peux utiliser setFrame, et cela fonctionne. Y a-t-il un moyen de contourner ceci? Je veux vraiment utiliser la mise en page automatique, car cela aide à rendre l'application agréable sur l'iphone 5 et les appareils antérieurs. Mais je voudrais également utiliser setFrame dans ma sous-classe, pour me faciliter la vie un peu.

Pour résumer, ma question est: puis-je utiliser la mise en page automatique et également ajuster le cadre d'une UIView par programme?

62
SirRupertIII

Oui, cela peut être fait.

Si vous définissez le translatesAutoresizingMaskIntoConstraints = YES, puis appelle à setFrame: sont automatiquement traduits au moment de l'exécution en contraintes de mise en page en fonction du autoresizingMask actuel de la vue. Cela vous permet de mélanger une disposition basée sur des cadres avec une disposition basée sur des contraintes.

Par exemple, vous pouvez utiliser la disposition automatique pour définir la disposition de toutes les sous-vues d'une vue, mais toujours appeler setFrame: pour définir la taille et la position de la vue elle-même. De votre point de vue, vous faites la mise en page avec un mélange de mise en page automatique et de manipulation directe de trame. Mais le système utilise en fait des contraintes pour tout gérer.

Cependant, il y a une grande mise en garde concernant l'utilisation de translatesAutoresizingMaskIntoConstraints.

Lorsque vous faites cela, vous devez toujours vous assurer que ces contraintes automatiques peuvent être satisfaites avec le reste de vos contraintes .

Donc, par exemple, supposons qu'il existe déjà des contraintes qui déterminent la taille et la position de votre vue, puis vous également définissez translatesAutoresizingMaskIntoConstraints = YES et appelé setFrame:. L'appel à setFrame: générera de nouvelles contraintes sur la vue, ce qui sera probablement en conflit avec les contraintes déjà existantes.

(En fait, cette erreur se produit souvent. Si vous voyez un message de journal se plaindre de contraintes conflictuelles, et l'une de ces contraintes est un NSAutoresizingMaskLayoutConstraint, alors ce que vous voyez est un conflit avec une contrainte automatique. est une erreur facile, car translatesAutoresizingMaskIntoConstraints = YES est la valeur par défaut, donc si vous configurez des contraintes dans le code, vous devez vous rappeler de le désactiver si vous ne voulez pas ces contraintes automatiques.)

En revanche, supposons à nouveau qu'il existe déjà des contraintes qui déterminent la taille et la position de votre vue, mais vous définissez ensuite translatesAutoresizingMaskIntoConstraints = NO avant d'appeler setFrame:. Dans ce cas, votre setFrame: les appels ne produiraient pas de nouvelles contraintes, il n'y aurait donc pas de conflit entre des contraintes distinctes . Cependant, dans ce cas, il existe toujours un "conflit" entre les contraintes et la valeur de trame que vous définissez . Lors de la prochaine invocation de la mise en page automatique, elle verrait les contraintes déjà existantes sur la vue, calculerait la valeur de trame dont elles ont besoin et définirait la trame sur la valeur requise elle-même, encombrant la valeur que vous définissez manuellement.

Pour plus de détails, consultez la section "Adoption de la mise en page automatique" dans Apple Cocoa Auto Layout Guide .

203
algal

Ce qui s'est avéré être la chose la plus simple pour moi a été de supprimer la vue que je voulais déplacer/redimensionner de sa vue d'ensemble, de définir son frame, puis de l'ajouter à nouveau. Par exemple, prenez un UILabel personnalisé dans une sous-classe UITableViewCell:

[cell.myLabel removeFromSuperview];
cell.myLabel.frame = someFrameIGenerated;
[cell.contentView addSubview:cell.myLabel];
16
Andrew

Quelque chose qui a fonctionné pour moi consistait simplement à ajouter un IBOutlet pour mes contraintes au contrôleur de vue, puis à modifier la propriété constant sur la sortie.

Par exemple, pour modifier l'origine x d'une vue, définissez une sortie de la contrainte principale de cette vue vers votre contrôleur. En d'autres termes, créez une prise @IBOutlet var labelXOrigin: NSLayoutConstraint!. Ensuite, lorsque vous souhaitez régler la position x, faites simplement quelque chose comme

self.labelXOrigin.constant = 20.0 // Or whatever Origin you want to set.
3
Nick Yap

la meilleure façon de définir le cadre de la sous-vue est la méthode viewWillLayoutSubviews dans les projets de mise en page automatique.

set property translationsAutoresizingMaskIntoConstraints = true cela fonctionnera après que la vue soit apparue ou tabulation sur le bouton pour définir, juste après que la vue soit apparue.

2
Ravi Kumar

Si votre application ne prend pas en charge plusieurs orientations d'appareil.

Dans viewDidLoad définissez le cadre de la vue que vous souhaitez redimensionner

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [aView setFrame:CGRectMake(15, 15, 100, 100)];
}

Puis dans viewDidLayoutSubviews:

-(void)viewDidLayoutSubviews
{
    [self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
}

Je ne suis pas sûr mais je pense que si vous utilisez cette solution, passer d'une orientation à une autre pourrait causer des problèmes

0
EFE