Il semble qu'avec Xcode 8, viewDidLoad
toutes les sous-vues du contrôleur de vue aient la même taille de 1000x1000. Chose étrange, mais d'accord, viewDidLoad
n'a jamais été le meilleur endroit pour dimensionner correctement les vues.
Mais viewDidLayoutSubviews
est-ce!
Et sur mon projet actuel, j'essaye d'imprimer la taille d'un bouton:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
NSLog(@"%@", self.myButton);
}
Le journal affiche une taille de (1000x1000) pour myButton! Ensuite, si je me connecte sur un bouton, par exemple, le journal affiche une taille normale.
J'utilise la mise en page automatique.
Est-ce un bug?
ios
autolayout
ios10
xcode8
Martin
la source
la source
(0, 0, 1000, 1000)
initialisation liée est la nouvelle façon dont Xcode instancie les vues d'IB. Avant Xcode8, les vues étaient créées avec leur taille configurée dans le xib, puis redimensionnées en fonction de l'écran juste après. Mais maintenant, il n'y a pas de taille configurée dans le document IB car la taille dépend de la sélection de votre appareil (en bas de l'écran). La vraie question est donc: y a-t-il un endroit fiable où la taille finale des vues pourrait être vérifiée?Réponses:
Désormais, Interface Builder permet à l'utilisateur de modifier dynamiquement la taille de chaque contrôleur de vue dans le storyboard, pour simuler la taille d'un certain appareil.
Avant cette fonctionnalité, l'utilisateur doit définir manuellement chaque taille de contrôleur de vue. Ainsi, le contrôleur de vue a été enregistré avec une certaine taille, qui a été utilisée
initWithCoder
pour définir l'image initiale.Maintenant, il semble que
initWithCoder
n'utilisez pas la taille définie dans le storyboard et définissez une taille de 1000x1000 px pour la vue du contrôleur de vue et toutes ses sous-vues.Ce n'est pas un problème, car les vues doivent toujours utiliser l'une de ces solutions de mise en page:
mise en page automatique, et toutes les contraintes mettront correctement en page vos vues
autoresizingMask, qui mettra en page chaque vue à laquelle aucune contrainte n'est attachée ( notez que les contraintes de mise en page automatique et de marge sont désormais compatibles dans la même vue \ o /! )
Mais c'est un problème pour tous les éléments de mise en page liés au calque de vue, comme
cornerRadius
, car ni la mise en page automatique ni le masque de redimensionnement automatique ne s'appliquent aux propriétés du calque.Pour répondre à ce problème, la méthode courante consiste à utiliser
viewDidLayoutSubviews
si vous êtes dans le contrôleur, oulayoutSubview
si vous êtes dans une vue. À ce stade (n'oubliez pas d'appeler leurssuper
méthodes relatives), vous êtes à peu près sûr que tout le travail de mise en page a été fait!Assez sûr? Hum ... pas totalement, j'ai remarqué, et c'est pourquoi j'ai posé cette question, dans certains cas, la vue a toujours sa taille 1000x1000 sur cette méthode. Je pense qu'il n'y a pas de réponse à ma propre question. Pour donner le maximum d'informations à ce sujet:
1- cela n'arrive que lors de la disposition des cellules! Dans les
UITableViewCell
&UICollectionViewCell
sous-classes,layoutSubview
ne sera pas appelé après que les sous- vues soient correctement disposées.2- Comme l'a fait remarquer @EugenDimboiu (veuillez voter pour sa réponse si cela est utile pour vous), appeler la
[myView layoutIfNeeded]
sous-vue non disposée la mettra en page correctement juste à temps.3- A mon avis, c'est définitivement un bug. Je l'ai soumis au radar (id 28562874).
PS: je ne suis pas anglophone, alors n'hésitez pas à modifier mon message si ma grammaire doit être corrigée;)
PS2: Si vous avez une meilleure solution, n'hésitez pas à écrire une autre réponse. Je vais proposer la réponse acceptée.
la source
UIStackView
intérieur d'unUICollectionViewCell
ne retournait pas une hauteur correcte pendantviewDidLayoutSubviews
. L'appel alayoutIfNeeded
immédiatement corrigé le problème.Utilisez-vous des coins arrondis pour votre bouton? Essayez d'appeler
layoutIfNeeded()
avant.la source
Solution: Wrap tout à l' intérieur
viewDidLayoutSubviews
deDispatchQueue.main.async
.la source
-viewDidLoad
... une solution de contournement aussi étrangeJe sais que ce n'était pas votre question exacte, mais j'ai rencontré un problème similaire où, comme lors de la mise à jour, certaines de mes vues ont été faussées malgré la taille d'image correcte dans viewDidLayoutSubviews. Selon les notes de version d'iOS 10:
Essentiellement, vous ne pouvez pas appeler layoutIfNeeded sur un objet enfant de View si vous utilisez translatesAutoresizingMaskIntoConstraints - maintenant l'appel de layoutIfNeeded doit être sur le superView, et vous pouvez toujours l'appeler dans viewDidLayoutSubviews.
la source
Si les cadres ne sont pas corrects dans layoutSubViews (ce qu'ils ne sont pas), vous pouvez envoyer un peu de code asynchrone sur le thread principal. Cela laisse au système le temps de faire la mise en page. Lorsque le bloc que vous envoyez est exécuté, les cadres ont leurs tailles appropriées.
la source
Cela a résolu le problème (ridiculement ennuyeux) pour moi:
Edit / Note: Ceci est pour un ViewController plein écran.
la source
[super viewDidLayoutSubviews];
cette méthode en raison de nombreuses tâches de mise en page automatique effectuées par la vue elleUIView
s. Mais si vous devez effectuer un calcul spécial sur un certain cadre de vue, la réponse d'Eugen fonctionne: appelez-layoutIfNeeded
le. J'ai le sentiment que ce n'est pas la meilleure solution, mais je n'ai toujours pas trouvé mieux.En fait, ce
viewDidLayoutSubviews
n'est pas non plus le meilleur endroit pour définir le cadre de votre vue. D'après ce que j'ai compris, à partir de maintenant, le seul endroit où cela devrait être fait est lalayoutSubviews
méthode dans le code de la vue réelle. J'aurais aimé ne pas avoir raison, quelqu'un me corrige s'il vous plaît si ce n'est pas vrai!la source
viewDidLayoutSubviews
est assez ambiguë. La deuxième phrase des «discussions» contredit en quelque sorte la dernière. developer.apple.com/reference/uikit/uiviewcontroller/…J'ai déjà signalé ce problème à Apple, ce problème existe depuis longtemps, lorsque vous initialisez UIViewController à partir de Xib, mais j'ai trouvé une solution de contournement assez intéressante. En plus de cela, j'ai trouvé ce problème dans certains cas lorsque layoutIfNeeded sur UICollectionView et UITableView lorsque la source de données n'est pas définie au moment initial et que je devais également la swizzler.
Envoi une fois l'extension:
Extension Swizzle:
la source
Mon problème a été résolu en modifiant l'utilisation de
à
Donc, de Did à Will
Super bizarre
la source
Meilleure solution pour moi.
En utilisant
la source
Remplacer la mise en page Les éditeurs (du calque: CALayer) au lieu de la mise en page Les sous-vues dans la sous-vue de la cellule pour avoir des cadres corrects
la source
Si vous avez besoin de faire quelque chose en fonction du cadre de votre vue, remplacez layoutSubviews et appelez layoutIfNeeded
J'ai eu le problème avec viewDidLayoutSubviews renvoyant le mauvais cadre pour ma vue, pour laquelle je devais ajouter un dégradé. Et seul layoutIfNeeded a fait la bonne chose :)
la source
Selon la nouvelle mise à jour d'ios, il s'agit en fait d'un bogue mais nous pouvons le réduire en utilisant -
Si vous utilisez xib avec la mise en page automatique dans votre projet, vous devez simplement mettre à jour le cadre dans le paramètre de mise en page automatique, veuillez trouver une image pour cela.
la source