2016-02-08 8 views
9

Ich lerne über benutzerdefinierte Ansichten und wollte mehr über invalidate() und requestLayout() erfahren.Warum wird requestLayout direkt nach dem Ungültigmachen aufgerufen

Bitte auf diese Antwort und seine Diagramm:

https://stackoverflow.com/a/25846243/4243687

invalidate() Android sagt, dass der Zustand der Ansicht geändert wurde und neu gezeichnet werden.

requestLayout() bedeutet, dass die Größe der Ansicht möglicherweise geändert wurde und erneut gemessen und dann neu gezeichnet werden muss.

invalidate() ruft dispatchDraw(), draw() und onDraw() auf, daher rendert es die Ansicht neu.

requestLayout() auf der anderen Seite macht so ziemlich alles vom Messen bis zum erneuten Rendern.

Warum so viele der Beispiele da draußen (auch die TextView Quellcode) rufen Sie invalidate() und dann requestLayout() direkt auf der nächsten Zeile?

Antwort

11

invalidate() wird speziell zum Neuzeichnen des Inhalts Ihrer Ansicht verwendet. Das Neuzeichnen erfolgt nicht synchron. Stattdessen wird der Bereich Ihrer Ansicht als ungültig markiert, sodass er während des nächsten Renderzyklus neu gezeichnet wird.

requestLayout() sollte verwendet werden, wenn etwas in ihm möglicherweise seine Abmessungen geändert hat. In diesem Fall müssen sich die Elternansicht und alle anderen Eltern in der Ansichtshierarchie über einen Layout-Durchlauf neu anpassen.

Wenn Sie nichts tun, um Ihre Größe zu ändern, müssen Sie nicht requestLayout() anrufen.

Wenn Sie zurückgehen und die Stellen im Code für TextView betrachten, in denen requestLayout() aufgerufen wird, wird es auf Methoden, wo die Grenzen der Ansicht betroffen sein wird. Zum Beispiel setPadding(), setTypeface(), setCompoundDrawables() usw.

Also, wenn requestLayout() genannt wird, soll es mit einem Aufruf gekoppelt wird ungültig zu machen, um sicherzustellen, dass die gesamte Ansicht neu gezeichnet wird.

+0

Vielen Dank für die große Erklärung so entkräften() und requestLayout() aufgerufen zusammen, um unsere Sichtweise neu zu zeichnen und auch die Elterngruppe (die unsere Ansicht als Kind hat) sich anzupassen, ist gut für mögliche Größenänderungen unserer Sicht zu berücksichtigen, wenn wir wieder zeichnen –

+1

Ich bin ein wenig unklar, wie warum würden Sie 'invalidate()' aufrufen, wenn Sie auch 'requestLayout()' aufrufen. Es scheint, als würde 'requestLayout()' immer dazu führen, dass Ihre gesamte Ansicht neu gezeichnet wird; Darüber hinaus erscheint der Aufruf von 'invalidate()' überflüssig. – pathfinderelite

+0

@pathfinderelite Stellen Sie sich vor, wenn Sie ein lineares Layout haben, das den Inhalt umschließt, wird es nur so groß wie das, was innerhalb des linearen Layouts ist. Stellen Sie sich vor, ich hätte eine Textansicht. Wenn ich setText() aufruft, muss ich invalidate() aufrufen, um den neuen Text so darzustellen, dass er angezeigt wird. Jetzt könnte dieser Text das TextView größer machen, also muss ich requestLayout() aufrufen, um dem linearen Layout (dem Elternteil, das die Textansicht enthält) zu sagen, dass du die Größe ändern musst, damit du die TextView anpassen kannst, die jetzt mehr Text –

0

Android docs: Creating a View class

public boolean isShowText() { 
    return mShowText; 
} 

public void setShowText(boolean showText) { 
    mShowText = showText; 
    invalidate(); 
    requestLayout(); 
} 

Beachten Sie, dass Anrufe ungültig machen() und requestLayout() setShowText. Diese Aufrufe sind entscheidend, um sicherzustellen, dass sich die Ansicht zuverlässig verhält. Sie haben , um die Ansicht nach jeder Änderung an ihren Eigenschaften ungültig zu machen, die sein Aussehen ändern könnte, so dass das System weiß, dass es neu gezeichnet werden muss. Entsprechend müssen Sie ein neues Layout anfordern, wenn sich eine Eigenschaft ändert, die sich auf die Größe oder Form der Ansicht auswirken kann. Wenn diese Methodenaufrufe vergessen werden, können schwer zu findende Fehler auftreten.

2

Relevante Auszug aus dem Buch Expert Android, die die Frage beantwortet:

Da das OnClick-Ereignis der Dimensionen, braucht unsere Ansicht zu ändern verursacht hat, größer zu werden und mehr Platz in Anspruch nehmen. Wie drücken wir aus, die zu Android benötigen, Nun, wir fordern Layout() an. Diese Methode geht in die Kette über und markiert jedes View-Elternelement, das erneut gemessen werden muss. Wenn das endgültige übergeordnete Element diese Anforderung (das Ansichtsstammverzeichnis) erhält, plant das übergeordnete Element ein Layout-Traversal. Ein Layout-Traversal kann in OnDraw ergeben oder nicht, obwohl es in diesem Fall sollte. Als eine gute Programmierung Praxis, nennen wir auch invalidate(), um die Zeichnungsphase als gut zu gewährleisten.

4

Nach the following diagram sah, war ich den Eindruck, unter, dass requestLayout() Aufruf schließlich in einem onDraw führen würde.

enter image description here

Daher wäre es keine Notwendigkeit, diese zusammen zu nennen, weil es überflüssig wäre.

invalidate(); 
requestLayout(); 

Es stellt sich jedoch heraus, dass dieses Diagramm irreführend ist. Einige Ansichten können sich bei einer Layoutänderung sogar selbst ungültig machen, dies ist jedoch keine Gewissheit. Der Aufruf von requestLayout() führt nicht garantiert dazu, dass onDraw aufgerufen wird.

Mein source (dank this comment) ist der Romain Guy (die ein Android-Ingenieur bei Google ist):

requestLayout() sich nicht zu einem Unentschieden Pass führen, aber einige Ansichten könnte eine reagieren Layoutänderung durch Aufruf von invalidate.

daher sicher sein, ein neues Layout in einem Neuaufbau führen, dann sollten Sie ein invalidate() mit den requestLayout() paaren. (Das Gegenteil ist nicht wahr, wenn. Wenn Sie nur einen Neuaufbau benötigen, dann gibt es keine Notwendigkeit requestLayout() zu nennen ist. Eine einzelne invalidate() tun wird.)

Verwandte Themen