Je ne parle pas de la propriété frame, car à partir de là, vous ne pouvez obtenir la taille de la vue que dans le xib. Je parle du moment où la vue est redimensionnée en raison de ses contraintes (peut-être après une rotation, ou en réponse à un événement). Existe-t-il un moyen d'obtenir sa largeur et sa hauteur actuelles?
J'ai essayé d'itérer ses contraintes à la recherche de contraintes de largeur et de hauteur, mais ce n'est pas très clair et échoue lorsqu'il y a des contraintes intrinsèques (car je ne peux pas faire la différence entre les deux). De plus, cela ne fonctionne que s'ils ont réellement des contraintes de largeur et de hauteur, ce qu'ils ne font pas s'ils s'appuient sur d'autres contraintes pour redimensionner.
Pourquoi est-ce si difficile pour moi. ARG!
la source
Réponses:
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
etview.bounds.size.height
(ou le cadre, qui est équivalent à moins que vous ne jouiez avec leview.transform
).Si vous voulez la largeur et la hauteur impliquées par vos contraintes existantes, la réponse n'est pas d'inspecter les contraintes manuellement, car cela vous obligerait à réimplémenter toute la logique de résolution de contraintes du système de mise en page automatique afin de les interpréter. contraintes. Au lieu de cela, vous devez simplement demander à la disposition automatique de mettre à jour cette disposition , afin qu'elle résout les contraintes et mette à jour la valeur de view.bounds avec la solution correcte, puis vous inspectez la vue.bounds.
Comment demander à la mise en page automatique de mettre à jour la mise en page? Appelez
[view setNeedsLayout]
si vous voulez que la disposition automatique mette à jour la disposition au prochain tour de la boucle d'exécution.Cependant, si vous souhaitez qu'il mette à jour immédiatement la mise en page, afin de pouvoir accéder immédiatement à la nouvelle valeur de limites ultérieurement dans votre fonction actuelle, ou à un autre moment avant le tour de la boucle d'exécution, vous devez appeler
[view setNeedsLayout]
et[view layoutIfNeeded]
.Vous avez posé une deuxième question: "comment puis-je changer une contrainte hauteur / largeur si je n'y ai pas de référence directement?".
Si vous créez la contrainte dans IB, la meilleure solution consiste à créer un IBOutlet dans votre contrôleur de vue ou dans votre vue pour y faire directement référence. Si vous avez créé la contrainte dans le code, vous devez conserver une référence dans une propriété faible interne 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 sur la vue, et éventuellement toute la hiérarchie de vues, et en implémentant une logique qui trouve le NSLayoutConstraint crucial. Ce n'est probablement pas la bonne façon de procéder, car cela vous oblige également à déterminer quelle contrainte particulière a déterminé la taille des limites, alors qu'il n'est pas garanti qu'il y ait une réponse simple à cette question. La valeur finale des bornes pourrait être la solution à un système très compliqué de contraintes multiples,
la source
layoutIfNeeded
est génial, et rendra le cadre immédiatement disponible. Cependant, cela forcera également le rendu des contraintes sur toutes les vues dans les sous-arbres de la vue sur laquelle il est appelé. Si vous ajoutez des vues par programme, par exemple, et que vous les appelezlayoutIfNeeded
toutes dans votre routine récursive, vous constaterez peut-être que votre hiérarchie de vues s'affiche très lentement. (J'ai appris cela à la dure) Comme mentionné dans l'excellente réponse, «setNeedsLayout» est plus efficace et rendra le cadre disponible lors de la prochaine passe de mise en page, ce qui se produit idéalement en 1 / 60e de seconde environ.initWithCoder
?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 sa configuration de contraintes dans leUIStoryboard
. J'ai pu accéder aux contraintes mises à jour avec- (void)viewDidLayoutSubviews
. Ceci est utile pour ne pas avoir besoin de sous-classer une vue et de remplacer sa méthode de disposition.Sans appeler la méthode à partir de la
viewDidLayoutSubview
méthode, seule la bordure supérieure est dessinée correctement, car la bordure inférieure est quelque part hors écran.la source
[super viewDidLayoutSubviews];
Pour ceux qui peuvent encore être confrontés à de tels problèmes, en particulier avec TableviewCell.
Remplacez simplement la méthode:
Dans le cas de UITableViewCell ou UICollectionViewCell, créez une sous-classe de la cellule et remplacez la même méthode:
la source
Utiliser
-(void)viewWillAppear:(BOOL)animated
et appeler[self.view layoutIfNeeded];
- Cela fonctionne, j'ai essayé.car si vous l'utilisez,
-(void)viewDidLayoutSubviews
cela fonctionnera certainement, 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éenne pour éviter une telle boucle d'appels. meilleure utilisationviewWillAppear
. RememberviewWillAppear
sera également appelé si la vue est à nouveau chargée (sans réallocation).la source
Le cadre est toujours valide. En fin de compte, la vue utilise sa propriété frame pour se mettre en page. Il calcule ce cadre en fonction de toutes les contraintes. Les contraintes ne sont utilisées que pour la mise en page initiale (et à tout moment, layoutSubviews est appelée 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?
la source