Je ne parle pas de la propriété frame, car à partir de là, vous ne pouvez obtenir que la taille de la vue dans le fichier xib. Je parle du fait que la vue est redimensionnée en raison de ses contraintes (peut-être après une rotation ou en réponse à un événement). Y a-t-il un moyen d'obtenir sa largeur et sa hauteur actuelles?
J'ai essayé de parcourir ses contraintes en cherchant des contraintes de largeur et de hauteur, mais ce n'est pas très clair et ça échoue quand il y a des contraintes intrinsèques (étant donné que je ne peux pas différencier les deux). En outre, cela ne fonctionne que s'ils ont réellement des contraintes de largeur et de hauteur, ce qui n'est pas le cas s'ils s'appuient sur d'autres contraintes pour redimensionner.
Pourquoi est-ce si difficile pour moi? ARG!
La réponse est [view layoutIfNeeded]
.
Voici pourquoi:
Vous obtenez toujours la largeur et la hauteur actuelles de la vue en inspectant view.bounds.size.width
et view.bounds.size.height
_ (ou le cadre, qui est équivalent à moins que vous ne jouiez avec le view.transform
).
Si ce que vous voulez est la largeur et la hauteur impliquées par vos contraintes existantes, la réponse est de ne pas inspecter les contraintes manuellement, car cela vous obligerait à réimplémenter toute la logique de résolution de contraintes du système de présentation automatique. Au lieu de cela, vous devez simplement demander à la présentation automatique de mettre à jour cette disposition , de manière à résoudre les contraintes et à mettre à jour la valeur de view.bounds avec solution correcte, puis vous inspectez les view.bounds.
Comment demandez-vous à la mise en page automatique de mettre à jour la mise en page? Appel [view setNeedsLayout]
si vous souhaitez que la disposition automatique mette à jour la disposition lors du prochain tour de la boucle d’exécution.
Cependant, si vous souhaitez que la mise à jour soit immédiatement mise à jour, afin que vous puissiez accéder immédiatement à la nouvelle valeur des limites plus tard dans votre fonction actuelle, ou à un autre moment avant le début de la boucle d'exécution, vous devez alors: appel [view setNeedsLayout]
et [view layoutIfNeeded]
.
Vous avez posé une deuxième question: "Comment puis-je modifier une contrainte hauteur/largeur si je n’ai pas de référence directe à cela?".
Si vous créez la contrainte dans IB, la meilleure solution consiste à créer un IBOutlet dans votre contrôleur de vue ou votre vue afin que vous puissiez vous y référer directement. Si vous avez créé la contrainte dans le code, vous devez conserver une référence dans une propriété interne faible au moment où vous l'avez créée. Si quelqu'un d'autre a créé la contrainte, vous devez la trouver en examinant la propriété view.constraints de la vue, et éventuellement toute la hiérarchie de la vue, et en implémentant une logique qui recherche l'élément crucial NSLayoutConstraint. C’est probablement la mauvaise façon d’agir, car elle vous oblige également à déterminer quelle contrainte particulière a déterminé la taille des limites, lorsque la réponse à cette question n’est pas garantie. La valeur des limites finales pourrait être la solution à un système très complexe de contraintes multiples, de priorités multiples, etc., de sorte qu'aucune contrainte ne constitue la "cause" de la valeur finale.
J'ai eu un problème similaire où je devais ajouter une bordure supérieure et inférieure à un UITableView
qui se redimensionne en fonction de la configuration de ses contraintes dans le UIStoryboard
. J'ai pu accéder aux contraintes mises à jour avec - (void)viewDidLayoutSubviews
. Cela est utile pour éviter de sous-classer une vue et de remplacer sa méthode de présentation.
/*** SET TOP AND BOTTOM BORDERS ON TABLE VIEW ***/
- (void)addBorders
{
CALayer *topBorder = [CALayer layer];
topBorder.frame = CGRectMake(0.0f, self.tableView.frame.Origin.y, 320.0f, 0.5f);
topBorder.backgroundColor = [UIColor redColor].CGColor;
CALayer *bottomBorder = [CALayer layer];
bottomBorder.frame = CGRectMake(0.0f, (self.tableView.frame.Origin.y + self.tableView.frame.size.height), 320.0f, 0.5f);
bottomBorder.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:topBorder];
[self.view.layer addSublayer:bottomBorder];
}
/*** GET AUTORESIZED FRAME DIMENSIONS ***/
- (void)viewDidLayoutSubviews{
[self addBorders];
}
Sans appeler la méthode à partir de la méthode viewDidLayoutSubview
, seule la bordure supérieure est dessinée correctement, la bordure inférieure étant quelque part à l’écran.
Pour ceux qui peuvent encore être confrontés à de tels problèmes, en particulier avec TableviewCell.
Suffit de remplacer la méthode:
-(void)layoutSubviews
{
//your code here like drawing a shadow
}
Dans le cas de UITableViewCell ou UICollectionViewCell, créez une sous-classe de la cellule et substituez la même méthode:
-(void)layoutSubviews
{
//your code here like drawing a shadow
}
Utilisez -(void)viewWillAppear:(BOOL)animated
et appelez [self.view layoutIfNeeded];
- Cela fonctionne, j'ai essayé.
parce que si vous utilisez -(void)viewDidLayoutSubviews
, cela fonctionnera définitivement, mais cette méthode est appelée à chaque fois que votre interface utilisateur demande des mises à jour/modifications. Ce qui sera difficile à gérer. La touche programmable est que vous utilisez une variable bool pour éviter une telle boucle d'appels. mieux utiliser viewWillAppear
. Rappelez-vous que viewWillAppear
sera également appelé si view est chargé de nouveau (sans réaffectation).
Le cadre est toujours valide. En fin de compte, la vue utilise sa propriété frame pour se présenter. Il calcule ce cadre en fonction de toutes les contraintes. Les contraintes ne sont utilisées que pour la présentation initiale (et chaque fois que layoutSubviews est appelé sur une vue comme après une rotation). Après cela, les informations de position se trouvent dans la propriété frame. Ou voyez-vous autrement?