Risposte:
Per comprendere meglio le risposte fornite da François BOURLIEUX e Dalvik, ti suggerisco di dare un'occhiata a questo fantastico diagramma del ciclo di vita di Arpit Mathur :
TextView
. Ho pensato che forse vogliono disegnare View
per l'ultima volta prima di cambiare i parametri relativi al layout, ma non ha davvero senso se pensiamo a quelle chiamate invocate nel diverso ordine (e chiamano invalidate()
subito dopo requestLayout()
in TextView
anche). Forse merita un'altra domanda su StackOverflow :)?
invalidate()
e requestLayout()
) correttamente. Lo scopo di questi metodi è di dire View
che tipo di invalidazione (come l'hai chiamata tu) è avvenuta. Non è come View
decide quale percorso seguire dopo aver chiamato uno di questi metodi. La logica dietro la scelta del View
-lifecycle-path è la scelta del metodo corretto per chiamare se stesso. Se c'è qualcosa legato alla modifica della dimensione - requestLayout()
dovrebbe essere chiamato, se c'è solo una modifica visiva senza una modifica della dimensione - dovresti chiamare invalidate()
.
View
in qualche modo la dimensione del tuo , ad esempio ottieni correnteLayoutParams
di un View
e li modifichi, ma NON chiami uno requestLayout
o setLayoutParams
(che chiama requestLayout
internamente), allora puoi chiamare invalidate()
quanto vuoi, e il View
non passerà attraverso il processo di misura layout, quindi non cambierà la sua dimensione. Se non dici al tuo View
che le sue dimensioni sono cambiate (con una requestLayout
chiamata al metodo), allora View
supporrà che non sia cambiato e onMeasure
e onLayout
non verrà chiamato.
invalidate()
La chiamata invalidate()
viene effettuata quando si desidera pianificare un ridisegno della vista. Alla fine verrà onDraw
chiamato (presto, ma non immediatamente). Un esempio di quando una vista personalizzata lo chiamerebbe è quando una proprietà del colore del testo o dello sfondo è cambiata.
La vista verrà ridisegnata ma le dimensioni non cambieranno.
requestLayout()
Se cambia qualcosa nella tua vista che influirà sulla dimensione, dovresti chiamare requestLayout()
. Questo attiverà onMeasure
e onLayout
non solo per questa vista ma fino in fondo per le viste principali.
NonrequestLayout()
è garantito che laonDraw
chiamata dia luogo a (contrariamente a quanto implica il diagramma nella risposta accettata), quindi di solito è combinata con invalidate()
.
invalidate();
requestLayout();
Un esempio di ciò è quando un'etichetta personalizzata ha la proprietà text modificata. L'etichetta cambierebbe dimensione e quindi dovrebbe essere rimisurata e ridisegnata.
forceLayout()
Quando è presente un oggetto requestLayout()
chiamato in un gruppo di viste padre, non è necessario rimisurare e inoltrare le viste figlio. Tuttavia, se un bambino deve essere incluso nella rimisurazione e nel relè, è possibile chiamare forceLayout()
il bambino. forceLayout()
Funziona su un bambino solo se si verifica in congiunzione con un requestLayout()
suo genitore diretto. La chiamata forceLayout()
da sola non avrà alcun effetto poiché non attiva un requestLayout()
albero di visualizzazione.
Leggi le domande e risposte per una descrizione più dettagliata di forceLayout()
.
requestLayout()
prima invalidate()
se vuoi. Nessuno dei due fa un layout o disegna immediatamente. Piuttosto, impostano flag che alla fine si tradurranno in un relayout e ridisegna.
Qui puoi trovare qualche risposta: http://developer.android.com/guide/topics/ui/how-android-draws.html
Per me una chiamata invalidate()
aggiorna solo la vista e una chiamata per requestLayout()
aggiornare la vista e calcolare la dimensione della vista sullo schermo.
usi invalidate () su una vista che vuoi ridisegnare, invocherà il suo onDraw (Canvas c) per invocare, e requestLayout () farà eseguire nuovamente il rendering dell'intero layout (fase di misurazione e fase di posizionamento). Dovresti usarlo se stai modificando le dimensioni della vista figlio in fase di esecuzione ma solo in casi particolari come vincoli dalla vista padre (intendo che l'altezza o la larghezza del padre sono WRAP_CONTENT e quindi abbina misura i bambini prima che possano avvolgerli di nuovo)
Questa risposta non è correttaforceLayout()
.
Come puoi vedere nel codice diforceLayout()
, la vista viene semplicemente contrassegnata come "necessita di un relayout" ma non pianifica né attiva quel relayout. Il relayout non avverrà fino a quando, in futuro, il genitore della view non sarà disposto per qualche altro motivo.
C'è anche un problema molto più grande quando si utilizza forceLayout()
e requestLayout()
:
Supponiamo che tu abbia richiamato forceLayout()
una vista. Ora quando si chiama requestLayout()
un discendente di quella vista, Android chiamerà ricorsivamente requestLayout()
gli antenati di quel discendente. Il problema è che interromperà la ricorsione nella vista su cui hai chiamato forceLayout()
. Quindi la requestLayout()
chiamata non raggiungerà mai la radice della vista e quindi non pianificherà mai un passaggio di layout. Un'intera sottostruttura della gerarchia della vista è in attesa di un layout e la chiamata requestLayout()
a qualsiasi vista di tale sottostruttura non causerà un layout. Richiamare requestLayout()
qualsiasi vista al di fuori di quella sottostruttura interromperà l'incantesimo.
Considererei l'implementazione di forceLayout()
(e il modo in cui influisce requestLayout()
per essere rotto e non dovresti mai usare quella funzione nel tuo codice.
View
e incappando nel problema da solo e eseguendo il debug.
forceLayout()
dell'API: in realtà non impone un passaggio di layout, piuttosto cambia solo un flag che viene osservato inonMeasure()
, ma onMeasure()
non verrà chiamato a meno che non venga chiamato requestLayout()
un esplicito View#measure()
. Ciò significa che forceLayout()
dovrebbe essere associato requestLayout()
. D'altra parte, perché allora esibirmi forceLayout()
se devo ancora esibirmi requestLayout()
?
requestLayout()
fa tutto ciò che forceLayout()
fa anche.
forceLayout
ha senso. Quindi alla fine ha solo un nome e una documentazione pessimi.
invalidate()
---> onDraw()
dal thread dell'interfaccia utente
postInvalidate()
---> onDraw()
dal thread di sfondo
requestLayout()
---> onMeasure()
ed onLayout()
E non necessariamente onDraw()
forceLayout()
---> onMeasure()
e onLayout()
SOLO SE il genitore diretto ha chiamato requestLayout()
.