J'ai une vue personnalisée qui ne reçoit pas les messages layoutSubview
lors de l'animation.
J'ai une vue qui remplit l'écran. Une sous-vue personnalisée en bas de l'écran se redimensionne correctement dans Interface Builder si je modifie la hauteur de la barre de navigation. layoutSubviews
est appelé lors de la création de la vue, mais plus jamais. Mes vues secondaires sont correctement présentées. Si je désactive la barre d'état en cours d'appel, la layoutSubviews
de la sous-vue n'est pas appelée du tout, même si la vue principale anime son redimensionnement.
Dans quelles circonstances layoutSubviews
est-il appelé?
autoresizesSubviews
est défini sur NO
pour ma vue personnalisée. Et dans Interface Builder, j'ai les entretoises supérieure et inférieure et le jeu de flèches verticales.
J'ai suivi la solution jusqu'à l'insistance d'Interer Builder sur le fait que les ressorts ne peuvent pas être modifiés dans une vue sur laquelle les éléments d'écran simulés sont activés (barre d'état, etc.). Étant donné que les ressorts étaient désactivés pour la vue principale, cette vue ne pouvait pas changer de taille et était donc entièrement défilée vers le bas lorsque la barre In-Call est apparue.
La désactivation des fonctionnalités simulées, puis le redimensionnement de la vue et le réglage correct des ressorts ont provoqué l’animation et l’appel de ma méthode.
Un problème supplémentaire lors du débogage est que le simulateur quitte l'application lorsque l'état de l'appel en cours est activé via le menu. Quittez app = pas de débogueur.
J'avais une question similaire, mais je n'étais pas satisfaite de la réponse (ni de celle que je pouvais trouver sur le net), alors je l'ai essayée en pratique et voici ce que j'ai obtenu:
init
ne cause pas layoutSubviews
àbe appelé (duh) addSubview:
provoque l’appel de layoutSubviews
sur la vue en cours d’ajout, la vue à laquelle elle est ajoutée (vue cible) et toutes les sous-vues de la cible.setFrame
appelle intelligemment layoutSubviews
sur la vue dont le cadre est défini uniquement si le paramètre de taille du cadre est différentlayoutSubviews
sur le scrollView et son aperçulayoutSubview
sur la vue parent (la vue primaire répondant à viewControllers )layoutSubviews
sur son aperçuMes résultats - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
En me basant sur la réponse précédente de @BadPirate, j’ai essayé un peu plus loin et proposé quelques clarifications/corrections. J'ai trouvé que layoutSubviews:
sera appelé sur une vue si et seulement si:
Quelques détails pertinents:
layoutSubviews:
est appelé chaque fois qu'un UIScrollView défile, car il effectue le défilement en modifiant l'origine de ses limites.layoutSubviews:
lorsque la vue est finalement ajoutée à une hiérarchie de vues.setNeedsLayout
, ce qui définit/déclenche un indicateur. A chaque itération de la boucle d'exécution, cet indicateur est activé pour toutes les vues de la hiérarchie de vues. layoutSubviews:
est appelé pour chaque vue où le drapeau est levé, et le drapeau est réinitialisé. Les vues situées plus haut dans la hiérarchie seront vérifiées/appelées en premier.Des changements de mise en page peuvent survenir chaque fois que l'un des événements suivants se produit dans une vue:
une. La taille du rectangle de contour d’une vue change.
b. Un changement d'orientation de l'interface se produit, ce qui déclenche généralement une modification du rectangle des limites de la vue racine.
c. L'ensemble des sous-couches de Core Animation associé au calque de la vue change et nécessite une mise en page.
ré. Votre application force la mise en page en appelant la méthodesetNeedsLayout
oulayoutIfNeeded
d'une vue.
e. Votre application force la présentation en appelant la méthodesetNeedsLayout
de l’objet calque sous-jacent de la vue.
Certains des points de la réponse de BadPirate ne sont que partiellement vrais:
Pour addSubView
point
addSubview
provoque l'appel de layoutSubviews sur la vue ajoutée, la vue à laquelle elle est ajoutée (vue cible) et toutes les sous-vues de la cible.
Cela dépend du masque de redimensionnement automatique de la vue (vue cible). Si Masque de taille automatique est activé, layoutSubview sera appelée à chaque addSubview
. Si elle n’a pas de masque de redimensionnement automatique, layoutSubview ne sera appelée que lorsque la taille de l’image de la vue (Vue cible) sera modifiée.
Exemple: si vous avez créé UIView par programme (il ne possède pas de masque de redimensionnement automatique par défaut), LayoutSubview sera appelée uniquement lorsque le cadre UIView ne sera pas modifié à chaque addSubview
.
C'est grâce à cette technique que les performances de l'application augmentent également.
Pour le point de rotation de l'appareil
La rotation d'un périphérique appelle uniquement layoutSubview sur la vue parent (la vue principale du viewController qui répond)
Cela ne peut être vrai que lorsque votre VC est dans la hiérarchie VC (racine à window.rootViewController
), ce qui est le cas le plus courant. Dans iOS 5, si vous créez un VC, mais qu'il n'est pas ajouté à un autre VC, ce VC ne sera pas remarqué lors de la rotation du périphérique. Par conséquent, sa vue ne serait pas remarquée en appelant layoutSubviews.
appeler [self.view setNeedsLayout];
dans viewController permet d'appeler viewDidLayoutSubviews
avez-vous regardé layoutIfNeeded?
L'extrait de documentation est ci-dessous. L'animation fonctionne-t-elle si vous appelez explicitement cette méthode pendant l'animation?
layoutIfNeeded Décale les vues secondaires si nécessaire.
- (void)layoutIfNeeded
Discussion Utilisez cette méthode pour forcer la mise en page des vues secondaires avant le dessin.
Disponibilité Disponible sur iPhone OS 2.0 et versions ultérieures.
Lors de la migration d'une application OpenGL du SDK 3 à 4, layoutSubviews n'était plus appelé. Après de nombreux essais et erreurs, j'ai finalement ouvert MainWindow.xib, sélectionné l'objet Window, dans l'inspecteur, sélectionné l'onglet Attributs de la fenêtre (à l'extrême gauche) et coché la case "Visible au lancement". Il semble que dans le SDK 3, il était toujours utilisé pour provoquer un appel layoutSubViews, mais pas dans 4.
6 heures de frustration terminées.
Une autre partie du puzzle est que la fenêtre doit être rendue clé:
[window makeKeyAndVisible];
sinon les sous-vues ne sont pas automatiquement redimensionnées.
Un cas plutôt obscur, mais potentiellement important, où layoutSubviews
n'est jamais appelé, est le suivant:
import UIKit
class View: UIView {
override class var layerClass: AnyClass { return Layer.self }
class Layer: CALayer {
override func layoutSublayers() {
// if we don't call super.layoutSublayers()...
print(type(of: self), #function)
}
}
override func layoutSubviews() {
// ... this method never gets called by the OS!
print(type(of: self), #function)
}
}
let view = View(frame: CGRect(x: 0, y: 0, width: 100, height: 100))