Jestem nieco mylić o rolach forceLayout()
, requestLayout()
i invalidate()
metod View
klasy.
Kiedy oni zostaną wezwani?
android
android-layout
android-view
sdabet
źródło
źródło
TextView
. Myślałem, że może chcą zwrócićView
się po raz ostatni, zanim zmieni swoje parametry związane z układu, ale to nie ma żadnego sensu, jeśli myślimy o tych rozmów powołano w innej kolejności (i nazywająinvalidate()
zaraz porequestLayout()
wTextView
także). Może zasługuje na inne pytanie na StackOverflow :)?invalidate()
irequestLayout()
). Celem tych metod jest poinformowanie,View
jaki rodzaj unieważnienia (jak to nazwałeś) miał miejsce. To nie jest tak, żeView
decyduje, którą ścieżką podążać po wywołaniu jednej z tych metod.View
Logiką wyboru ścieżki -lifecycle jest wybór właściwej metody, która ma się nazywać. Jeśli jest coś związanego ze zmianą rozmiaru -requestLayout()
należy nazywać, jeśli jest tylko zmiana wizualna bez zmiany rozmiaru - należy zadzwonićinvalidate()
.View
w jakiś sposób swój rozmiar , np. Uzyskasz prądLayoutParams
aView
i zmodyfikujesz je, ale NIE zadzwonisz albo,requestLayout
anisetLayoutParams
(który dzwonirequestLayout
wewnętrznie), możesz zadzwonićinvalidate()
tyle, ile chcesz, iView
nie przejdzie przez proces miara DTP, zatem nie będzie zmienić jego rozmiar. Jeżeli nie mówView
, że jego wielkość uległa zmianie (zrequestLayout
wywołania metody), wtedyView
będzie zakładać, że nie, aonMeasure
ionLayout
nie zostanie wywołana.invalidate()
Wywoływanie
invalidate()
odbywa się, gdy chcesz zaplanować przerysowanie widoku. Spowoduje to, żeonDraw
zostanie ostatecznie wywołany (wkrótce, ale nie natychmiast). Przykładem wywołania widoku niestandardowego jest zmiana właściwości koloru tekstu lub tła.Widok zostanie przerysowany, ale rozmiar się nie zmieni.
requestLayout()
Jeśli coś w twoim widoku zmieni się, co wpłynie na rozmiar, powinieneś zadzwonić
requestLayout()
. Spowoduje toonMeasure
, aonLayout
nie tylko dla tego widoku, ale aż do góry linii do poglądów dominujących.Wywołanie
requestLayout()
jest nie gwarantują wyniku wonDraw
(w przeciwieństwie do tego, co schemat w przyjętym odpowiedź wskazuje), więc to jest zwykle połączone zinvalidate()
.Przykładem tego jest zmiana właściwości tekstowej etykiety niestandardowej. Etykieta zmieniłaby rozmiar, w związku z czym należy ją poprawić i przerysować.
forceLayout()
Kiedy istnieje
requestLayout()
nadrzędna grupa widoków, nie trzeba ponownie oceniać i przekazywać jej widoków potomnych. Jeśli jednak dziecko powinno zostać włączone do ponownej oceny i przekazania, możesz je wezwaćforceLayout()
.forceLayout()
działa tylko na dziecko, jeśli występuje w połączeniu zrequestLayout()
jego bezpośrednim rodzicem. WywołanieforceLayout()
sam będzie miał żadnego wpływu, ponieważ nie wyzwolićrequestLayout()
się widoku drzewa.Przeczytaj te pytania i odpowiedzi, aby uzyskać bardziej szczegółowy opis
forceLayout()
.Dalsze badanie
View
kod źródłowyźródło
requestLayout()
wcześniej,invalidate()
jeśli chcesz. Żaden z nich nie tworzy układu ani nie rysuje natychmiast. Zamiast tego ustawiają flagi, które ostatecznie skutkują sztafetą i przerysowaniem.Tutaj znajdziesz odpowiedź: http://developer.android.com/guide/topics/ui/how-android-draws.html
Dla mnie wezwanie do
invalidate()
odświeżenia widoku i wezwanie dorequestLayout()
odświeżenia widoku i obliczenia rozmiaru widoku na ekranie.źródło
użyjesz validate () w widoku, który chcesz przerysować, spowoduje to wywołanie jego onDraw (Canvas c), a requestLayout () spowoduje ponowne uruchomienie renderowania całego układu (faza pomiaru i faza pozycjonowania). Powinieneś go użyć, jeśli zmieniasz rozmiar widoku potomnego w środowisku wykonawczym, ale tylko w szczególnych przypadkach, takich jak ograniczenia z widoku rodzica (rozumiem przez to, że wysokość lub szerokość rodzica są WRAP_CONTENT i dlatego dopasuj zmierz dzieci, zanim będą mogły je ponownie owinąć)
źródło
Ta odpowiedź jest nieprawidłowa
forceLayout()
.Jak widać w kodzie
forceLayout()
, zaznacza on widok jako „potrzebuje przekaźnika”, ale nie planuje ani nie wyzwala tego przekaźnika. Przekazywanie nastąpi dopiero w pewnym momencie, w którym rodzic widoku został ustanowiony z innego powodu.Istnieje również znacznie większy problem podczas używania
forceLayout()
irequestLayout()
:Powiedzmy, że wywołałeś
forceLayout()
widok. Teraz, gdy wzywamyrequestLayout()
potomka tego widoku, Android będzie rekurencyjnie wzywałrequestLayout()
przodków tego potomka. Problem polega na tym, że zatrzyma rekurencję w widoku, do którego zadzwoniłeśforceLayout()
. Tak więcrequestLayout()
połączenie nigdy nie osiągnie katalogu głównego widoku, a zatem nigdy nie planuje przejścia układu. Całe poddrzewo hierarchii widoku czeka na układ, a wywołanierequestLayout()
dowolnego widoku tego poddrzewa nie spowoduje układu. Tylko wywołanierequestLayout()
dowolnego widoku poza tym poddrzewem złamie czar.Zastanowiłbym się nad implementacją
forceLayout()
(i jak to wpływarequestLayout()
na uszkodzenie i nigdy nie powinieneś używać tej funkcji w swoim kodzie).źródło
View
i sam napotykając problem, i debugując go.forceLayout()
API: nie wymusza to przejścia przez układ, a jedynie zmienia flagę, która jest obserwowanaonMeasure()
, aleonMeasure()
nie zostanie wywołana, chyba że zostanie wywołanerequestLayout()
jawneView#measure()
. Oznacza to, żeforceLayout()
należy to połączyćrequestLayout()
. Z drugiej strony, po co więc wykonywać,forceLayout()
jeśli nadal muszę występowaćrequestLayout()
?requestLayout()
robi wszystko, coforceLayout()
również.forceLayout
ma sens. W końcu jest to po prostu bardzo źle nazwane i udokumentowane.invalidate()
--->onDraw()
z wątku interfejsu użytkownikapostInvalidate()
--->onDraw()
z wątku w tlerequestLayout()
--->onMeasure()
ionLayout()
I niekoniecznieonDraw()
forceLayout()
--->onMeasure()
ionLayout()
JEŚLI JEŚLI bezpośredni rodzic zadzwoniłrequestLayout()
.źródło