2015-11-26 13 views
5

Zunächst sollte ich erwähnen, das ist vor allem ein Effizienzproblem.Frame-Berechnungen in `viewDidLayoutSubviews`

Es gibt viele Diskussionen, wo Frame-Berechnungen zu tun sind, wo viewWillAppear zu früh ist und viewDidAppear zu spät ist (Sicht ist bereits sichtbar).

Die allgemeine Antwort ist, Frame-Berechnungen in viewDidLayoutSubviews zu tun. Problem ist, dass es mehrmals aufgerufen wird. Schlimmer noch, der genaueste Anruf, bei dem alle Frames ihre endgültige Größe haben, ist der letzte. Nach meinem Wissen gibt es keine Möglichkeit zu wissen, welcher Anruf der letzte ist.

Wir verwenden eine ‚framesAreSet‘ Flag haben (initialisiert false) und eine Überprüfung, wo, wenn Rahmen nicht Null ist (wie self.view.frame.size.width != 0 etwas) und ‚framesAreSet‘ falsch ist, es geht in die Fahne ab und berechnen nur einmal . Etwas wie:

- (void)viewDidLayoutSubviews 
{ 
    [super viewDidLayoutSubviews]; 

    if (self.view.frame.size.width != 0 && !framesAreSet) 
    { 
     framesAreSet = true; 

     //Calculate frames here 
    } 
} 

Das sieht in Ordnung, aber in Wahrheit, eine Prüfung für so etwas wie self.view.frame.size.width != 0 tut nicht Garantie, dass Frames ist in der Tat ein. Die Tatsache, dass viewDidLayoutSubviews danach aufgerufen wird, legt nahe, dass einige Frames nicht auf ihren Endstatus gesetzt wurden.

Wäre toll, eine viewCompleteLayoutSubviews zu haben. Irgendwelche Ideen darüber, was der beste Weg ist, um eine 'einmalige' Rahmenberechnung durchzuführen, wenn alle Rahmen gesetzt und angezeigt werden, ist noch nicht sichtbar?

(Dies ist wahrscheinlich ein Problem mit Blick nicht mit NSConstraints)

+1

Warum ist es ein Problem, dass 'viewDidLayoutSubviews' mehr als einmal aufgerufen wird? Welches Problem haben Sie? – rmaddy

+0

Werden Sie zufällig die Grenzen von 'self.view' darin aktualisieren? Wenn das so ist, ist das dein Problem. – Clafou

+0

@rmaddy Redundanz ist keine gute Kodierungspraxis. Angenommen, Sie haben einen komplexen ViewController, fügen viele Subviews im Code hinzu (die in der Tat größtenteils im Code erstellt wurden) und führen viele Berechnungen für Einstellungsrahmen durch. Stellen Sie sich vor, Sie hätten "schwere" Berechnungen so oft, wie Sie Subviews plus hinzufügen. Wohlgemerkt, alle außer dem letzten sind überflüssig. Manchmal ist es nicht gut genug. – bauerMusic

Antwort

1

Die App erhält nur eine didLayoutSubviews pro Zeichnung (bis zu diesem Punkt, Ansicht Zustand Änderungen sind nur notiert mit setNeedsLayout). In diesem Sinne ist didLayoutSubviews Ihre Idee von didCompleteLayoutOfSubviews. Wenn nach der Zeichnung eine Änderung des Ansichtsstatus eintritt, ist das Layout erneut unvollständig.

Mit anderen Worten, die Anzahl der didLayout-Aufrufe hängt nicht von der Anzahl der Subview-Adds oder Frame-Änderungen ab, sie hängt von der Anzahl der Draws ab (nicht zu verwechseln mit der Run-Schleife). Wenn vor dem Zeichnen das needsLayout-Flag gesetzt wurde, werden layoutSubviews und didLayoutSubviews genau einmal aufgerufen, unabhängig davon, wie weit die Ansichtshierarchie neu angeordnet wurde.

+0

Wenn ich richtig verstehe, hängt die Anzahl der Aufrufe von 'didLayoutSubviews' (abgesehen von der ursprünglichen) von meiner Änderung ab (Frame ändern, Unteransicht hinzufügen) im Code. Das heißt, es ist vorhersehbar und ich kann eine Flagge nach meinem letzten "didLayoutSubviews trigger" haben, nach dem 'didLayoutSubviews' zum letzten Mal (für diesen Zyklus) aufgerufen wird? – bauerMusic

+1

Ich glaube nicht, dass dein Verständnis völlig richtig ist. Die Anzahl der didLayout-Aufrufe hängt nicht von der Anzahl der Subview-Adds oder Frame-Änderungen ab, sie hängt von der Anzahl der Draws ab (nicht zu verwechseln mit der Run-Schleife). Wenn vor dem Zeichnen das needsLayout-Flag gesetzt wurde, werden layoutSubviews und didLayoutSubviews genau einmal aufgerufen, unabhängig davon, wie weit die Ansichtshierarchie neu angeordnet wurde. – danh

+0

Gute Antwort. Es wäre toll, wenn Sie Ihrer Antwort Ihren letzten Kommentar hinzufügen könnten, ich werde ihn als "akzeptiert" bezeichnen. Ich muss herausfinden, wo meine Ansichten aufgerufen werden, um nach den anfänglichen 'layoutSubviews' zu zeichnen. Aber das ist eine etwas andere Frage. Vielen Dank! – bauerMusic

0

Sie Rahmen in viewDidLayoutSubviews Methode berechnen kann mit Versand einmal Token (GCD), dass, wenn Frames einmal initialisiert werden diese innen nicht Ihre bekommen Versandblock.

+0

Great Punkt ausgelöst wird. Für meinen Zweck würde ich mich jedoch nicht anders verhalten als eine Flagge. Außerdem gibt es das Problem, den letzten und aktuellsten Aufruf von "viewDidLayoutSubviews" zu "fangen". – bauerMusic

+0

Aber ich denke nicht, dass wir den letzten Anruf in ViewDisLayoutSubview bekommen können .... Sie können Frame-Berechnungen in ViewWillAppear tun. – Abhishek

+0

Wie ich geschrieben habe, haben 'viewWillAppear' Frames unter verschiedenen Bedingungen nicht ihre endgültige Größe. – bauerMusic

1

Sie sollten immer für die Dimension, die Ihre Ansicht aktuell hat, neu anordnen.

Sie legen die Frames fest, dann drehen Sie das Gerät. Müssen Sie die Frames neu berechnen? Sicher hast du, die Größe hat sich geändert! Sie machen gefährliche Annahmen mit Ihrer framesAreSet.

Wenn Leistung wirklich der Schlüssel für Sie ist, möchten Sie möglicherweise die berechneten Frames ein paar Wörterbücher im Cache speichern, wenn die Grenzen Größe ändert.

Aber Sie werden sicherlich nicht mit der Durchführung Layout nur einmal durchkommen.

Eine Alternative wäre, den View Controller view eine Instanz einer benutzerdefinierten Klasse zu machen und -layoutSubviews dort zu überschreiben.

+0

_ "Sie machen gefährliche Annahmen mit Ihrem framesAreSet" _. Irgendwann ist es eingestellt, wie gesagt, "viewDidAppear". Betrachten Sie eine Ansicht, die sich nicht dreht. Ist es sinnvoll, dieselbe Berechnung mehrmals auszuführen? Schlimmer noch, wenn sich eine Ansicht dreht, sollte jede Drehung die Rahmenberechnung mehrere Male ausführen, wobei die einzige nützliche Zeit sie die letzte ist? – bauerMusic

+0

"Betrachten Sie eine Ansicht, die sich nicht dreht, macht es Sinn, dieselbe Berechnung mehrmals auszuführen?" - Ja, es gibt andere Dinge, die Ihre Ansicht verändern können. –

Verwandte Themen