dispatchDraw() — adalah metode kelas ViewGroup yang bertanggung jawab untuk menggambar secara rekursif semua View anak dalam hierarki Android. Menurut Android Developers Documentation (2026), dispatchDraw dipanggil secara otomatis setelah onDraw dalam metode draw() dari View utama dan menelusuri semua elemen anak, memanggil draw() mereka sendiri. Pengembang menimpa dispatchDraw di ViewGroup kustom untuk menambahkan efek, melapiskan grafik di atas anak, atau mengubah urutan penggambaran.
Utama
dispatchDraw(Canvas canvas) — adalah metode protected dari kelas ViewGroup yang dipanggil oleh sistem Android untuk menggambar semua View anak dari kontainer saat ini. dispatchDraw adalah bagian dari pipeline draw standar: pertama onDraw dieksekusi (menggambar konten View itu sendiri), kemudian dispatchDraw (penggambaran rekursif anak), kemudian onDrawForeground (menggambar foreground dan scrollbars). Metode ini tidak dimaksudkan untuk dipanggil langsung dari kode aplikasi.
Implementasi standar dispatchDraw di ViewGroup mengiterasi semua View anak, memeriksa visibilitasnya, dan memanggil draw(Canvas) untuk masing-masing. Urutan penelusuran sesuai dengan indeks anak (dari 0 hingga childCount - 1). Jika View anak saling tumpang tindih, yang terakhir dalam daftar digambar di atas yang pertama. Dengan mengubah urutan di dispatchDraw, Z-order penggambaran dapat diubah.
Untuk View (bukan ViewGroup) metode dispatchDraw kosong — View biasa tidak memiliki elemen anak, jadi tidak ada yang perlu digambar. Metode ini ada di kelas dasar View, tetapi hanya dipanggil untuk instance ViewGroup. Pengembang dapat memeriksa apakah View memiliki elemen anak melalui perilaku default dispatchDraw, tetapi seringkali lebih sederhana untuk memeriksa instanceof ViewGroup.
Metode draw(Canvas) dari kelas View mengatur pipeline penggambaran tiga tahap. Tahap pertama — pemanggilan onDraw(canvas), di mana View menggambar kontennya. Tahap kedua — pemanggilan dispatchDraw(canvas), yang memulai penggambaran View anak. Tahap ketiga — onDrawForeground(canvas), bertanggung jawab untuk lapisan foreground, scrollbars, dan efek ripple. Urutan ini menjamin tumpukan lapisan grafis yang benar.
onDraw selalu dieksekusi sebelum dispatchDraw. Ini berarti konten View induk ditampilkan di bawah View anak. Jika perlu menggambar sesuatu di atas anak, ini dilakukan di onDrawForeground atau di dispatchDraw yang ditimpa dengan pemanggilan super.dispatchDraw(canvas) dan penggambaran selanjutnya di atasnya. Latar belakang (background) digambar bahkan sebelum onDraw — di drawBackground(canvas) di dalam metode draw().
Pada percepatan perangkat keras (hardware acceleration) pipeline draw bekerja melalui GPU. View digambar dalam DisplayList — daftar perintah gambar yang di-cache dan digunakan kembali. dispatchDraw dalam mode percepatan perangkat keras menambahkan DisplayList View anak ke DisplayList umum adegan. Mengubah dispatchDraw dapat menyebabkan invalidasi DisplayList dan pembangunan ulang cache, yang memengaruhi kinerja.
| Metode | Urutan panggilan | Tujuan |
|---|---|---|
| drawBackground | 1 | Menggambar latar belakang (background drawable) |
| onDraw | 2 | Menggambar konten View itu sendiri |
| dispatchDraw | 3 | Menggambar semua View anak (hanya untuk ViewGroup) |
| onDrawForeground | 4 | Menggambar foreground, scrollbar, dan efek ripple |
onDraw bertanggung jawab untuk menggambar konten View itu sendiri — bentuk, teks, gambar yang menjadi milik elemen spesifik ini. dispatchDraw bertanggung jawab untuk menggambar View anak — semua elemen yang berada di dalam ViewGroup. Jika ViewGroup tidak menimpa dispatchDraw, implementasi dari ViewGroup digunakan, yang hanya secara rekursif menelusuri childCount dan memanggil draw untuk setiap anak.
Untuk ViewGroup yang tidak menggambar konten sendiri (misalnya, FrameLayout, LinearLayout), onDraw dapat dioptimalkan dengan mengatur setWillNotDraw(true). Dalam kasus ini, onDraw tidak pernah dipanggil, yang menghemat sumber daya. dispatchDraw tetap berfungsi dan memanggil draw untuk elemen anak. Semua ViewGroup standar (LinearLayout, RelativeLayout, ConstraintLayout) menggunakan setWillNotDraw(true).
Jika dispatchDraw ditimpa tanpa memanggil super.dispatchDraw(canvas), View anak tidak akan digambar. Ini dapat berguna untuk menyembunyikan sementara semua anak, tetapi dalam banyak kasus menyebabkan kesalahan. Praktik yang direkomendasikan: panggil super.dispatchDraw(canvas) di awal metode yang ditimpa, lalu tambahkan grafik Anda sendiri (misalnya, overlay dengan saluran alfa) di atas anak.
Mari buat OverlayViewGroup — ViewGroup kustom yang menambahkan lapisan semi-transparan dengan label teks di atas semua View anak. dispatchDraw pertama memanggil super (menggambar semua anak), kemudian menggambar persegi panjang overlay dan teks. Paint dibuat di konstruktor untuk menghindari alokasi dalam loop draw.
class OverlayViewGroup(context: Context)
: ViewGroup(context) {
private val overlayPaint = Paint().apply {
color = Color.parseColor("#66000000")
style = Paint.Style.FILL
}
private val textPaint = Paint().apply {
color = Color.WHITE
textSize = 36f
isAntiAlias = true
textAlign = Paint.Align.CENTER
}
init {
setWillNotDraw(false)
}
override fun dispatchDraw(canvas: Canvas) {
super.dispatchDraw(canvas)
canvas.drawRect(0f, 0f,
width.toFloat(),
height.toFloat(), overlayPaint)
canvas.drawText("MODE PRATINJAU",
width / 2f,
height / 2f, textPaint)
}
override fun onLayout(changed: Boolean,
l: Int, t: Int,
r: Int, b: Int) {
var top = t
for (i in 0 until childCount) {
val child = getChildAt(i)
val cw = child.measuredWidth
val ch = child.measuredHeight
child.layout(l, top, l + cw, top + ch)
top += ch
}
}
override fun onMeasure(widthMeasureSpec: Int,
heightMeasureSpec: Int) {
measureChildren(widthMeasureSpec, heightMeasureSpec)
val maxWidth = resolveSize(
getChildAt(0).measuredWidth,
widthMeasureSpec)
var totalHeight = 0
for (i in 0 until childCount) {
totalHeight += getChildAt(i).measuredHeight
}
setMeasuredDimension(maxWidth,
resolveSize(totalHeight, heightMeasureSpec))
}
}
Contoh berikut mendemonstrasikan perubahan urutan penggambaran elemen anak. CircularRevealLayout menimpa dispatchDraw dan menggambar anak dalam urutan terbalik, menciptakan efek Z-order terbalik. Untuk animasi, pergeseran siklik dari indeks penggambaran ditambahkan berdasarkan nilai offset yang dianimasikan.
class ReverseOrderLayout(context: Context)
: ViewGroup(context) {
private var reverse = false
override fun dispatchDraw(canvas: Canvas) {
if (!reverse) {
super.dispatchDraw(canvas)
return
}
for (i in childCount - 1 downTo 0) {
val child = getChildAt(i)
if (child.visibility == GONE) continue
drawChild(canvas, child, getDrawingTime())
}
}
fun toggleReverse() {
reverse = !reverse
invalidate()
}
override fun onLayout(changed: Boolean,
l: Int, t: Int,
r: Int, b: Int) {
var left = l
for (i in 0 until childCount) {
val child = getChildAt(i)
val cw = child.measuredWidth
child.layout(left, t,
left + cw, t + child.measuredHeight)
left += cw
}
}
override fun onMeasure(widthMeasureSpec: Int,
heightMeasureSpec: Int) {
measureChildren(widthMeasureSpec, heightMeasureSpec)
var totalWidth = 0
for (i in 0 until childCount) {
totalWidth += getChildAt(i).measuredWidth
}
setMeasuredDimension(
resolveSize(totalWidth, widthMeasureSpec),
resolveSize(getChildAt(0).measuredHeight,
heightMeasureSpec))
}
}
dispatchDraw digunakan dalam skenario di mana Anda perlu memengaruhi proses penggambaran View anak tanpa memengaruhi konten ViewGroup itu sendiri. Skenario utama: menerapkan efek bersama (overlay, shadow, gradient) di atas semua anak; mengubah urutan Z-order untuk menciptakan efek kedalaman; menganimasikan kemunculan atau penghilangan elemen anak melalui transformasi Canvas.
Jika diperlukan pelapisan grafik di bawah elemen anak (efek latar belakang), gunakan onDraw — dispatchDraw dipanggil setelahnya. Jika grafik harus di atas anak — gunakan dispatchDraw dengan panggilan super, lalu Canvas.draw. Jika diperlukan perubahan warna atau transparansi global, lebih mudah menggunakan canvas.saveLayerAlpha() di dispatchDraw yang membungkus penggambaran anak.
Tidak direkomendasikan menggunakan dispatchDraw untuk: 1) menggambar animasi kompleks secara real-time (gunakan invalidate dan onDraw); 2) membuat screenshot ViewGroup (gunakan buildDrawingCache() atau View.draw(Canvas)); 3) memodifikasi View anak (koordinat, ukuran — ini tugas onLayout, bukan dispatchDraw). dispatchDraw — hanya untuk menerapkan efek visual.
Pertanyaan yang Sering Diajukan
Tidak, dispatchDraw — metode protected yang dipanggil oleh sistem Android di dalam metode public draw(). Pemanggilan langsung dispatchDraw tidak berguna, karena tidak melakukan tindakan persiapan (menyimpan Canvas, menggambar latar belakang dan foreground). Sebagai gantinya, gunakan View.draw(Canvas) untuk penggambaran terprogram ke Canvas sembarang.
Jika Anda memanggil super.dispatchDraw(canvas) setelah operasi penggambaran Anda sendiri, View anak akan digambar di atas grafik kustom. Ini mengubah tumpukan lapisan: pertama lapisan kustom digambar, kemudian anak. Jika situasi sebaliknya diperlukan (grafik di atas anak), panggil super.dispatchDraw terlebih dahulu, lalu operasi Anda sendiri.
dispatchDraw memanggil draw() untuk setiap View anak, waktu total sebanding dengan jumlah anak. Pada hardware acceleration, penambahan operasi Canvas di dispatchDraw dapat menyebabkan invalidasi DisplayList dan pembangunan ulang cache. Untuk 5–10 anak dampaknya minimal, untuk 50+ anak disarankan untuk men-cache overlay yang kompleks.
View (bukan ViewGroup) tidak memiliki elemen anak, oleh karena itu dispatchDraw tidak melakukan pekerjaan yang berguna. Namun, metode ini ada di kelas dasar View untuk polimorfisme: kode di draw() memanggil dispatchDraw untuk View apa pun, tetapi implementasi View tidak berisi logika penggambaran anak. Hanya ViewGroup yang menimpa dispatchDraw.
Ya, dispatchDraw menerima Canvas dan dapat ditransformasi sebelum memanggil super.dispatchDraw (translate, rotate, scale). Ini diterapkan untuk menganimasikan seluruh set anak sebagai satu kesatuan. Setelah super.dispatchDraw selesai, disarankan untuk mengembalikan Canvas ke keadaan semula.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga