Jawaban:
Untuk lebih memahami jawaban yang diberikan oleh François BOURLIEUX dan Dalvik, saya sarankan Anda melihat diagram siklus hidup tampilan yang mengagumkan ini oleh Arpit Mathur :
TextView
. Saya pikir mungkin mereka ingin menggambar View
untuk yang terakhir kali sebelum mereka mengubah parameter yang berhubungan dengan tata letak, tetapi tidak benar-benar masuk akal jika kita berpikir tentang panggilan yang dipanggil dalam urutan yang berbeda (dan mereka memanggil invalidate()
tepat setelah requestLayout()
di TextView
demikian juga). Mungkin layak menerima pertanyaan lain tentang StackOverflow :)?
invalidate()
dan requestLayout()
) dengan benar. Tujuan dari metode-metode tersebut adalah untuk mengetahui View
jenis pembatalan seperti apa (sebagaimana Anda menyebutnya) telah terjadi. Ini tidak seperti View
memutuskan jalan apa yang harus diikuti setelah Anda memanggil salah satu metode itu. Logika di balik memilih View
-lifecycle-path adalah memilih metode yang tepat untuk memanggil dirinya sendiri. Jika ada sesuatu yang berkaitan dengan perubahan ukuran - requestLayout()
harus dipanggil, jika hanya ada perubahan visual tanpa ukuran diubah - Anda harus menelepon invalidate()
.
View
dalam beberapa cara, misalnya Anda mendapatkan arusLayoutParams
dari View
dan Anda mengubah mereka, tetapi tidak menyebut baik requestLayout
atau setLayoutParams
(yang panggilan requestLayout
internal), maka Anda dapat menghubungi invalidate()
sebanyak yang Anda inginkan, dan yang View
tidak akan melalui proses ukuran-layout, karena itu tidak akan mengubah ukurannya. Jika Anda tidak memberi tahu Anda View
bahwa ukurannya telah berubah (dengan requestLayout
pemanggilan metode), maka View
akan menganggap itu tidak, dan onMeasure
dan onLayout
tidak akan dipanggil.
invalidate()
Panggilan invalidate()
dilakukan saat Anda ingin menjadwalkan gambar ulang tampilan. Itu akan menghasilkan onDraw
dipanggil pada akhirnya (segera, tetapi tidak segera). Contoh kapan tampilan kustom menyebutnya adalah ketika properti teks atau warna latar belakang telah berubah.
Tampilan akan digambar ulang tetapi ukurannya tidak akan berubah.
requestLayout()
Jika ada sesuatu tentang perubahan tampilan Anda yang akan mempengaruhi ukuran, maka Anda harus menelepon requestLayout()
. Ini akan memicu onMeasure
dan onLayout
tidak hanya untuk tampilan ini tetapi juga sepanjang garis untuk tampilan induk.
Memanggil requestLayout()
ini tidak dijamin hasil dalamonDraw
(bertentangan dengan apa yang diagram dalam jawaban diterima menyiratkan), sehingga biasanya dikombinasikan dengan invalidate()
.
invalidate();
requestLayout();
Contoh dari ini adalah ketika label kustom memiliki properti teksnya diubah. Label akan berubah ukuran dan karenanya perlu diukur ulang dan digambar ulang.
forceLayout()
Ketika ada requestLayout()
yang dipanggil pada kelompok tampilan induk, itu tidak perlu untuk mengukur kembali dan menyampaikan pandangan anaknya. Namun, jika seorang anak harus dimasukkan dalam remeasure dan relayout, maka Anda dapat memanggilnya forceLayout()
. forceLayout()
hanya bekerja pada anak jika itu terjadi bersamaan dengan requestLayout()
pada orangtua langsungnya. Memanggil forceLayout()
dengan sendirinya tidak akan berpengaruh karena tidak memicu requestLayout()
pohon tampilan.
Baca Tanya Jawab ini untuk deskripsi yang lebih terperinci tentang forceLayout()
.
View
Kode sumberrequestLayout()
sebelumnya invalidate()
jika mau. Tidak ada yang melakukan tata letak atau menggambar segera. Sebaliknya, mereka menetapkan bendera yang pada akhirnya akan menghasilkan relayout dan redraw.
Di sini Anda dapat menemukan beberapa respons: http://developer.android.com/guide/topics/ui/how-android-draws.html
Bagi saya panggilan untuk invalidate()
hanya menyegarkan tampilan dan panggilan untuk requestLayout()
menyegarkan tampilan dan menghitung ukuran tampilan di layar.
Anda menggunakan invalidate () pada tampilan yang ingin Anda redraw, itu akan membuat onDraw (Canvas c) untuk dipanggil, dan requestLayout () akan membuat rendering seluruh layout (fase pengukuran dan fase positioning) berjalan kembali. Anda harus menggunakannya jika Anda mengubah ukuran tampilan anak saat runtime tetapi hanya dalam kasus-kasus tertentu seperti batasan dari tampilan induk (maksud saya bahwa tinggi atau lebar orangtua adalah WRAP_CONTENT dan karenanya cocok mengukur anak-anak sebelum mereka dapat membungkusnya lagi)
Jawaban ini tidak benar tentang forceLayout()
.
Seperti yang dapat Anda lihat dalam kodeforceLayout()
itu hanya menandai pandangan sebagai "membutuhkan relayout" tetapi tidak menjadwalkan atau memicu relayout itu. Relai tidak akan terjadi sampai pada suatu titik di masa depan orang tua tampilan diletakkan karena alasan lain.
Ada juga masalah yang jauh lebih besar saat menggunakan forceLayout()
dan requestLayout()
:
Katakanlah Anda telah meminta forceLayout()
tampilan. Sekarang ketika memanggil requestLayout()
keturunan dari pandangan itu, Android akan secara rekursif memanggil requestLayout()
leluhur keturunan itu. Masalahnya adalah itu akan menghentikan rekursi pada tampilan yang Anda panggil forceLayout()
. Jadi requestLayout()
panggilan tidak akan pernah mencapai view root dan dengan demikian tidak pernah menjadwalkan lulus tata letak. Seluruh subtree dari hierarki tampilan sedang menunggu tata letak dan memanggil requestLayout()
semua tampilan subtree tersebut tidak akan menyebabkan tata letak. Hanya memanggil requestLayout()
sembarang tampilan di luar subtree yang akan memecah mantra.
Saya akan mempertimbangkan implementasi forceLayout()
(dan bagaimana pengaruhnya requestLayout()
rusak dan Anda seharusnya tidak pernah menggunakan fungsi itu dalam kode Anda.
View
dan dengan menjalankan sendiri masalah tersebut & men-debug-nya.
forceLayout()
API: itu tidak benar-benar memaksa pass layout, melainkan hanya mengubah flag yang sedang diamationMeasure()
, tetapi onMeasure()
tidak akan dipanggil kecuali requestLayout()
atau secara eksplisit View#measure()
dipanggil. Itu berarti, itu forceLayout()
harus dipasangkan requestLayout()
. Di sisi lain, mengapa kemudian melakukan forceLayout()
jika saya masih perlu melakukan requestLayout()
?
requestLayout()
melakukan segala sesuatu yang forceLayout()
juga dilakukannya.
forceLayout
masuk akal. Jadi pada akhirnya nama dan dokumentasinya sangat buruk.
invalidate()
---> onDraw()
dari utas UI
postInvalidate()
---> onDraw()
dari utas latar belakang
requestLayout()
---> onMeasure()
dan onLayout()
DAN TIDAK onDraw()
forceLayout()
---> onMeasure()
dan onLayout()
HANYA JIKA induk langsung dipanggil requestLayout()
.