Ich bin ein wenig verwirrt über die Rolle von forceLayout()
, requestLayout()
und invalidate()
Methoden der View
Klasse.
Wann sollen sie gerufen werden?
android
android-layout
android-view
sdabet
quelle
quelle
TextView
. Ich dachte, dass sie das vielleichtView
zum letzten Mal zeichnen möchten, bevor sie ihre layoutbezogenen Parameter ändern, aber es macht keinen Sinn, wenn wir darüber nachdenken, dass diese Aufrufe in der anderen Reihenfolge aufgerufen werden (und sie rufeninvalidate()
direkt nachrequestLayout()
in aufTextView
auch). Vielleicht verdient es eine andere Frage zu StackOverflow :)?invalidate()
undrequestLayout()
) richtig verstehen . Der Zweck dieser Methoden besteht darin, festzustellen,View
welche Art von Ungültigmachung (wie Sie sie genannt haben) stattgefunden hat. Es ist nicht so, als würde manView
entscheiden, welchem Pfad man folgen soll, nachdem man eine dieser Methoden aufgerufen hat. Die Logik hinter der Auswahl desView
-lifecycle-Pfades ist die Auswahl der richtigen Methode, um sich selbst aufzurufen. Wenn es etwas im Zusammenhang mit Größenänderungen gibt -requestLayout()
sollte aufgerufen werden, wenn es nur eine visuelle Änderung ohne Größenänderung gibt - sollten Sie anrufeninvalidate()
.View
in irgendeiner Weise, zB Sie erhalten StromLayoutParams
von einView
und Sie ändern sie, aber nicht nennen entwederrequestLayout
odersetLayoutParams
(welche AnruferequestLayout
intern), dann können Sie anrufen ,invalidate()
so viel wie Sie wollen, und DasView
wird den Measure-Layout-Prozess nicht durchlaufen und daher seine Größe nicht ändern. Wenn Sie Ihrem nicht mitteilen,View
dass sich seine Größe geändert hat (mit einemrequestLayout
Methodenaufruf),View
wird davon ausgegangen, dass dies nicht der Fall ist , und dasonMeasure
undonLayout
wird nicht aufgerufen.invalidate()
Der Anruf
invalidate()
wird ausgeführt, wenn Sie ein erneutes Zeichnen der Ansicht planen möchten. Es wird dazu führen,onDraw
dass es irgendwann angerufen wird (bald, aber nicht sofort). Ein Beispiel dafür, wann eine benutzerdefinierte Ansicht sie aufrufen würde, ist, wenn sich eine Text- oder Hintergrundfarbeneigenschaft geändert hat.Die Ansicht wird neu gezeichnet, die Größe ändert sich jedoch nicht.
requestLayout()
Wenn sich etwas an Ihrer Ansicht ändert, das sich auf die Größe auswirkt, sollten Sie anrufen
requestLayout()
. Dies löstonMeasure
undonLayout
nicht nur für diese Ansicht aber den ganzen Weg bis die Leitung für die übergeordneten Ansichten.Es
requestLayout()
wird nicht garantiert, dass einonDraw
Anruf zu einem führt (im Gegensatz zu dem, was das Diagramm in der akzeptierten Antwort impliziert), daher wird es normalerweise mit kombiniertinvalidate()
.Ein Beispiel hierfür ist, wenn die Texteigenschaft einer benutzerdefinierten Beschriftung geändert wird. Das Etikett würde seine Größe ändern und muss daher neu gemessen und neu gezeichnet werden.
forceLayout()
Wenn
requestLayout()
eine übergeordnete Ansichtsgruppe aufgerufen wird, muss die untergeordnete Ansicht nicht erneut gemessen und weitergeleitet werden. Wenn jedoch ein Kind in die erneute Messung und Weiterleitung einbezogen werden soll, können SieforceLayout()
das Kind anrufen .forceLayout()
Funktioniert nur bei einem Kind, wenn es in Verbindung mit einemrequestLayout()
bei seinem direkten Elternteil auftritt . Das AufrufenforceLayout()
von sich selbst hat keine Auswirkung, darequestLayout()
der Ansichtsbaum nicht nach oben ausgelöst wird .Lesen Sie diese Fragen und Antworten für eine detailliertere Beschreibung von
forceLayout()
.Weitere Studie
View
Quellcodequelle
requestLayout()
vorher anrufen,invalidate()
wenn du willst. Keiner macht ein Layout oder zeichnet sofort. Vielmehr setzen sie Flags, die schließlich zu einem Relayout und einem Neuzeichnen führen.Hier finden Sie eine Antwort: http://developer.android.com/guide/topics/ui/how-android-draws.html
Für mich
invalidate()
aktualisiert ein Aufruf, nur die Ansicht zurequestLayout()
aktualisieren, und ein Aufruf, die Ansicht zu aktualisieren und die Größe der Ansicht auf dem Bildschirm zu berechnen.quelle
Wenn Sie invalidate () für eine Ansicht verwenden, die Sie neu zeichnen möchten, wird onDraw (Canvas c) aufgerufen, und requestLayout () lässt das gesamte Layout-Rendering (Messphase und Positionierungsphase) erneut ausgeführt werden. Sie sollten es verwenden, wenn Sie die Größe der untergeordneten Ansicht zur Laufzeit ändern, jedoch nur in bestimmten Fällen, z. B. Einschränkungen aus der übergeordneten Ansicht (damit meine ich, dass die übergeordnete Höhe oder Breite WRAP_CONTENT ist und daher die untergeordneten Elemente übereinstimmen, bevor sie sie erneut umbrechen können).
quelle
Diese Antwort ist nicht richtig
forceLayout()
.Wie Sie im Code sehen
forceLayout()
können, markiert die Ansicht lediglich die Ansicht als "benötigt ein Relayout", aber sie plant oder löst dieses Relayout weder aus. Das Relayout wird erst zu einem späteren Zeitpunkt stattfinden, wenn das übergeordnete Element der Ansicht aus einem anderen Grund festgelegt wurde.Es gibt auch ein viel größeres Problem bei der Verwendung von
forceLayout()
undrequestLayout()
:Angenommen, Sie haben
forceLayout()
eine Ansicht aufgerufen . Wenn Sie nunrequestLayout()
einen Nachkommen dieser Ansicht aufrufen, ruft Android rekursivrequestLayout()
die Vorfahren dieses Nachkommen auf. Das Problem ist, dass die Rekursion bei der Ansicht, die Sie aufgerufen haben, gestoppt wirdforceLayout()
. DerrequestLayout()
Aufruf erreicht also niemals den Ansichtsstamm und plant daher niemals einen Layoutdurchlauf. Ein ganzer Teilbaum der Ansichtshierarchie wartet auf ein Layout, und das AufrufenrequestLayout()
einer Ansicht dieses Teilbaums führt nicht zu einem Layout. NurrequestLayout()
wenn Sie eine Ansicht außerhalb dieses Teilbaums aufrufen , wird der Zauber gebrochen.Ich würde die Implementierung von
forceLayout()
(und wie es sich auswirktrequestLayout()
, wenn sie kaputt geht, in Betracht ziehen und Sie sollten diese Funktion niemals in Ihrem Code verwenden.quelle
View
und das Problem selbst festgestellt und es debuggt habe.forceLayout()
API: Sie erzwingt keinen Layout-Pass, sondern ändert nur ein Flag, das in beobachtetonMeasure()
wird,onMeasure()
wird aber nur aufgerufen, wennrequestLayout()
ein expliziterView#measure()
Aufruf erfolgt. Das heißt, dasforceLayout()
sollte gepaart werdenrequestLayout()
. Auf der anderen Seite, warum dann durchführen,forceLayout()
wenn ich noch durchführen mussrequestLayout()
?requestLayout()
macht alles wasforceLayout()
auch macht.forceLayout
macht Sinn. Am Ende ist es also nur sehr schlecht benannt und dokumentiert.invalidate()
--->onDraw()
vom UI-ThreadpostInvalidate()
--->onDraw()
aus dem Hintergrund-ThreadrequestLayout()
--->onMeasure()
undonLayout()
UND NICHT NOTWENDIGonDraw()
forceLayout()
--->onMeasure()
undonLayout()
NUR WENN der direkte Elternteil anruftrequestLayout()
.quelle