Ich habe in meiner Anwendung ein seltsames Verhalten festgestellt, bei dem eine verbundene IBOutlet
Ansicht den Rahmen ihrer verbundenen Ansicht zwischen den Aufrufen in meinem Ansichtscontroller an viewWillAppear:
und hat viewDidAppear:
. Hier ist der relevante Code in meiner UIViewController
Unterklasse:
-(void)viewWillAppear:(BOOL)animated {
NSLog(@"%@", self.scrollView);
}
-(void)viewDidAppear:(BOOL)animated {
NSLog(@"%@", self.scrollView);
}
und die resultierende Protokollausgabe:
MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 0; 0 0); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>
MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 44; 320 416); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>
Dies zeigt deutlich, dass sich der Frame zwischen den beiden Aufrufen ändert. Ich wollte das Setup mit der Ansicht in der viewDidLoad
Methode durchführen, aber wenn der Inhalt nicht verfügbar ist, um ihn zu ändern, bis er auf dem Bildschirm angezeigt wird, scheint dies ziemlich nutzlos zu sein. Was könnte passieren?
iphone
ios
objective-c
uiscrollview
Jumhyn
quelle
quelle
viewDidLayoutSubviews
war der richtige Weg. Ich musste nur meinen gesamten Inhalt in eine Unteransicht einfügen, damit die Methode nicht erneut aufgerufen wurde, wenn ich den Rahmen der Hauptansicht änderte.Antworten:
Autolayout
Wir haben die Art und Weise, wie wir die Benutzeroberfläche unserer Ansichten entwerfen und entwickeln, grundlegend geändert. Einer der Hauptunterschiede besteht darin, dassautolayout
sich unsere Ansichtsgrößen nicht sofort ändern, sondern nur, wenn sie ausgelöst werden, dh zu einem bestimmten Zeitpunkt. Wir können sie jedoch zwingen, unsere Einschränkungen sofort neu zu berechnen oder sie als "bedarfsbedürftig" für das Layout zu markieren. Es funktioniert wie-setNeedDisplay
.Die große Herausforderung für mich bestand darin, das zu verstehen und zu akzeptieren. Wir müssen keine Masken für die automatische Größenänderung mehr verwenden, und der Rahmen ist zu einer nutzlosen Eigenschaft beim Platzieren unserer Ansichten geworden. Wir müssen nicht mehr über die Ansichtsposition nachdenken, aber wir sollten darüber nachdenken, wie wir sie in einem Raum sehen wollen, der miteinander in Beziehung steht.
Wenn wir alte Autoresizing-Maske und Autolayout mischen möchten, treten Probleme auf. Wir sollten sehr bald über die Implementierung von Autolayout nachdenken und versuchen, den alten Ansatz nicht in eine auf Autolayout basierende Ansichtshierarchie zu mischen.
Es ist in Ordnung, eine Containeransicht zu haben, die nur Masken für die automatische Größenänderung verwendet, z. B. eine Hauptansicht eines Ansichtscontrollers. Es ist jedoch besser, wenn wir nicht versuchen, zu mischen.
Ich habe nie ein Storyboard verwendet, aber am wahrscheinlichsten ist es richtig. Mit Autolayout wird der Rahmen Ihrer Ansichten festgelegt, wenn die Autolayout-Engine ihre Berechnung startet. Versuchen Sie, das Gleiche direkt nach der Super-
- (void)viewDidLayoutSubviews
Methode Ihres View Controllers zu fragen .Diese Methode wird aufgerufen, wenn die Autolayout-Engine die Berechnung der Frames Ihrer Ansichten beendet hat.
quelle
add something on a screen, "just before it appears to the user". The actual answer is indeed to use viewDidLayoutSubviews.
... Sie werden diese Ansicht oft zeigenAus der Dokumentation:
Benachrichtigt den Ansichtscontroller, dass seine Ansicht einer Ansichtshierarchie hinzugefügt werden soll.
Benachrichtigt den Ansichtscontroller, dass seine Ansicht einer Ansichtshierarchie hinzugefügt wurde.
Infolgedessen sind die Frames der Unteransichten noch nicht in der
viewWillAppear
:Die geeignete Methode zum Ändern Ihrer Benutzeroberfläche, bevor die Ansicht auf dem Bildschirm angezeigt wird, ist:
Benachrichtigt den Ansichtscontroller, dass seine Ansicht gerade seine Unteransichten angelegt hat.
quelle
viewDidLayoutSubviews
dies mehrmals und nicht immer mit demselben Frame aufgerufen wird (ich denke, es wird manchmal beim ersten Aufruf mit CGRectZero aufgerufen). Es wird für jede hinzugefügte Unteransicht und andere Änderungen in der Ansicht aufgerufen.Anruf
in Ihrer
viewWillAppear
Methode. Danach können Sie auf den Rahmen zugreifen und er hat den gleichen Wert wie beim DruckenviewDidAppear
quelle
In meinem Fall verschieben Sie alle rahmenbezogenen Methoden nach
funktionierte perfekt (ich habe versucht, Einschränkungen aus dem Storyboard zu ändern).
quelle