Ich habe eine benutzerdefinierte Ansicht, die während der Animation keine layoutSubview
-Meldungen erhält.
Ich habe eine Ansicht, die den Bildschirm ausfüllt. Am unteren Bildschirmrand befindet sich eine benutzerdefinierte Unteransicht, deren Größe im Interface Builder korrekt geändert wird, wenn ich die Höhe der Navigationsleiste ändere. layoutSubviews
wird beim Erstellen der Ansicht aufgerufen, jedoch nie wieder. Meine Unteransichten sind korrekt angeordnet. Wenn ich die Statusleiste während eines Anrufs ausschalte, wird die layoutSubviews
der Unteransicht überhaupt nicht aufgerufen, obwohl die Hauptansicht ihre Größenänderung animiert.
Unter welchen Umständen wird layoutSubviews
tatsächlich aufgerufen?
Ich habe autoresizesSubviews
für meine benutzerdefinierte Ansicht auf NO
gesetzt. Und im Interface Builder habe ich die oberen und unteren Streben und den vertikalen Pfeil eingestellt.
Ich habe die Lösung auf die Behauptung von Interface Builder zurückverfolgt, dass Federn nicht in einer Ansicht geändert werden können, in der die simulierten Bildschirmelemente aktiviert sind (Statusleiste usw.). Da die Quellen für die Hauptansicht deaktiviert waren, konnte diese Ansicht ihre Größe nicht ändern und wurde daher vollständig abgescrollt, als die In-Call-Leiste erschien.
Das Deaktivieren der simulierten Funktionen, das Ändern der Ansichtsgröße und das korrekte Einstellen der Federn führten dazu, dass die Animation auftrat und meine Methode aufgerufen wurde.
Ein zusätzliches Problem beim Debuggen besteht darin, dass der Simulator die App beendet, wenn der Status während eines Anrufs über das Menü umgeschaltet wird. App beenden = kein Debugger.
Ich hatte eine ähnliche Frage, war aber mit der Antwort nicht zufrieden (oder was ich im Internet finden konnte), also habe ich es in der Praxis ausprobiert und hier ist was ich bekommen habe:
init
bewirkt nicht, dass layoutSubviews
aufgerufen wirdbe (duh) addSubview:
bewirkt, dass layoutSubviews
für die hinzugefügte -Ansicht aufgerufen wird. Die Ansicht wird hinzugefügt (Zielansicht) und alle Subviews des ZielssetFrame
ruft intelligent layoutSubviews
bei der Ansicht auf, für die nur der Frame festgelegt ist , wenn der Größenparameter des Frames unterschiedlich istlayoutSubviews
für die scrollView und deren Superview aufgerufenlayoutSubview
in der übergeordneten Ansicht aufgerufen (die antwortende viewControllers-Primäransicht ).layoutSubviews
im Übersichtsfenster aufgerufenMeine Ergebnisse - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
Aufbauend auf der vorherigen Antwort von @BadPirate experimentierte ich ein wenig weiter und kam zu einigen Klarstellungen/Korrekturen. Ich habe festgestellt, dass layoutSubviews:
nur dann aufgerufen wird, wenn:
Einige relevante Details:
layoutSubviews:
immer dann aufgerufen wird, wenn ein UIScrollView-Bildlauf ausgeführt wird, da der Bildlauf durch Ändern des Ursprungs der Begrenzungen durchgeführt wird.layoutSubviews:
, wenn die Ansicht schließlich einer Ansichtshierarchie hinzugefügt wird.setNeedsLayout
auf, wodurch ein Flag gesetzt wird. Bei jeder Wiederholung der Laufschleife wird für alle Ansichten in der Ansichtshierarchie dieses Flag geprüft. Für jede Ansicht, in der das Flag als angehoben gefunden wird, wird layoutSubviews:
für es aufgerufen und das Flag wird zurückgesetzt. Ansichten oberhalb der Hierarchie werden zuerst geprüft/aufgerufen.Layoutänderungen können auftreten, wenn eines der folgenden Ereignisse auftritt in einer Ansicht:
ein. Die Größe des Begrenzungsrechtecks einer Ansicht ändert sich.
b. Es kommt zu einer Änderung der Schnittstellenorientierung, die normalerweise eine Änderung des Begrenzungsrechtecks der Stammansicht auslöst.
c. Die mit der Ebenenebene der Ansicht verknüpften Satz von Kernanimations-Sublayern ändert sich und erfordert ein Layout.
d. Ihre Anwendung erzwingt das Auftreten des Layouts durch Aufrufen der MethodesetNeedsLayout
oderlayoutIfNeeded
einer Ansicht.
e. Ihre Anwendung erzwingt ein Layout, indem Sie diesetNeedsLayout
-Methode des darunter liegenden Layer-Objekts der Ansicht aufrufen.
Einige der Punkte in BadPirates Antwort sind nur teilweise zutreffend:
Für addSubView
Punkt
addSubview
bewirkt, dass layoutSubviews für die hinzugefügte Ansicht, die hinzugefügte Ansicht (Zielansicht) und alle Unteransichten des Ziels aufgerufen werden.
Dies hängt von der Autoresize-Maske der Ansicht (Zielansicht) ab. Wenn die Maske für die automatische Größenänderung aktiviert ist, wird layoutSubview für jedes addSubview
-Objekt aufgerufen. Wenn es keine Maske zum automatischen Ändern der Größe hat, wird layoutSubview nur aufgerufen, wenn sich die Bildgröße der Ansicht (Zielansicht) ändert.
Beispiel: Wenn Sie UIView programmgesteuert erstellt haben (es hat standardmäßig keine Maske zur automatischen Größenänderung), wird LayoutSubview nur aufgerufen, wenn sich der UIView-Frame nicht in jedem addSubview
ändert.
Durch diese Technik erhöht sich auch die Leistung der Anwendung.
Für den Gerätedrehpunkt
Beim Drehen eines Geräts wird nur layoutSubview in der übergeordneten Ansicht (der primären Ansicht des antwortenden viewControllers) aufgerufen.
Dies kann nur dann zutreffen, wenn sich Ihr VC in der Hierarchie VC befindet (root bei window.rootViewController
). Dies ist jedoch der häufigste Fall. Wenn Sie unter iOS 5 einen VC erstellen, aber nicht zu einem anderen VC hinzugefügt werden, wird dieser VC beim Drehen des Geräts nicht bemerkt. Daher wird seine Ansicht durch Aufrufen von layoutSubviews nicht bemerkt.
durch den Aufruf von [self.view setNeedsLayout];
in viewController wird viewDidLayoutSubviews aufgerufen
hast du dir LayoutIfNeeded angesehen?
Das Dokumentations-Snippet befindet sich unten. Funktioniert die Animation, wenn Sie diese Methode während der Animation explizit aufrufen?
layoutIfNeeded Legt die Unteransichten bei Bedarf aus.
- (void)layoutIfNeeded
Diskussion Verwenden Sie diese Methode, um das Layout von Unteransichten vor dem Zeichnen zu erzwingen.
Verfügbarkeit Verfügbar in iPhone OS 2.0 und höher.
Bei der Migration einer OpenGL-App von SDK 3 auf 4 wurde layoutSubviews nicht mehr aufgerufen. Nach langem Ausprobieren habe ich schließlich MainWindow.xib geöffnet, das Window-Objekt ausgewählt, im Inspektor die Registerkarte "Fensterattribute" (ganz links) ausgewählt und "Sichtbar beim Start" aktiviert. Es scheint, dass in SDK 3 noch ein Aufruf von layoutSubViews ausgelöst wurde, nicht aber in 4.
6 Stunden Frustration sind vorbei.
Ein weiterer Teil des Puzzles ist, dass das Fenster zum Schlüssel gemacht werden muss:
[window makeKeyAndVisible];
andernfalls wird die Größe der Unteransichten nicht automatisch geändert.
Ein ziemlich dunkler, aber möglicherweise wichtiger Fall, wenn layoutSubviews
niemals aufgerufen wird, lautet:
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))