onDraw() — apa itu, mekanisme pemanggilan dan override metode

Penulis: IT Sectr Diterbitkan: 2026-07-22 Waktu membaca: 10 mnt

onDraw() — adalah metode kunci dari kelas View di Android SDK, yang bertanggung jawab untuk merender konten tampilan. Sistem memanggil onDraw setiap kali tampilan View diperbarui — saat rendering awal, setelah invalidate() atau saat ukuran berubah. Menurut Android Developers Documentation (2026), override onDraw menggunakan Canvas API adalah cara utama untuk membuat grafis kustom di aplikasi Android.

Poin utama

  • onDraw(Canvas) — metode View yang dipanggil sistem untuk merender konten di Canvas
  • invalidate() — permintaan untuk menggambar ulang View, yang mengarah ke pemanggilan onDraw di siklus frame berikutnya
  • Canvas API menyediakan metode drawCircle, drawBitmap, drawText, drawPath dan lainnya untuk menggambar
  • Sistem Android menjalankan rendering di thread UI, oleh karena itu onDraw harus ringan dan cepat
  • Hardware acceleration secara otomatis mempercepat rendering melalui GPU, mulai dari Android 3.0 (API 11)

Apa itu onDraw()?

onDraw(Canvas canvas) — adalah metode protected dari kelas android.view.View, yang dipanggil oleh sistem Android ketika View perlu di-render. Pengembang meng-override metode ini untuk mengimplementasikan rendering kustom: bentuk, teks, gambar, gradien, animasi. Parameter Canvas adalah permukaan grafis di mana semua operasi menggambar dilakukan.

Sidik jari metode ini sederhana: override fun onDraw(canvas: Canvas). Di dalam metode ini tidak boleh membuat objek baru (untuk menghindari beban GC), melakukan operasi panjang atau bekerja dengan jaringan. View juga berisi metode onDraw dalam siklus hidupnya antara onLayout (perhitungan posisi) dan dispatchDraw (rendering elemen anak).

Saat mewarisi dari View, override onDraw wajib dilakukan untuk menampilkan konten apa pun — jika tidak, View akan kosong. Saat mewarisi dari subkelas yang ada (TextView, ImageView, Button), override onDraw bersifat opsional dan digunakan untuk menambahkan grafis tambahan di atas konten standar.

Siklus rendering View

Android menjalankan rendering View dalam urutan yang ditentukan secara ketat, dipanggil dari thread utama (UI thread). Siklus lengkap terdiri dari tiga fase: measure (pengukuran ukuran), layout (perhitungan posisi) dan draw (rendering). onDraw adalah bagian dari fase draw dan dipanggil setelah ukuran dan posisi View ditentukan.

Fase draw: dispatchDraw dan onDraw

draw(Canvas canvas) — adalah metode publik dari View yang memanggil onDraw dan dispatchDraw. Metode draw tidak dimaksudkan untuk di-override — sebagai gantinya, onDraw di-override. Setelah eksekusi onDraw untuk View saat ini, dispatchDraw dipanggil, yang secara rekursif memanggil draw untuk semua View anak (jika View saat ini adalah container ViewGroup).

Kapan sistem memanggil onDraw

onDraw dipanggil dalam kondisi berikut: 1) View menjadi terlihat untuk pertama kalinya (setelah setVisibility(VISIBLE)); 2) aplikasi memanggil invalidate() untuk View ini atau induknya; 3) ukuran View berubah (layout baru); 4) animasi yang terkait dengan View berubah (melalui ValueAnimator atau ObjectAnimator); 5) status View berubah (pressed, focused, enabled).

Percepatan hardware

Mulai Android 3.0 (API 11), sebagian besar operasi Canvas dijalankan dengan percepatan hardware melalui GPU. Pengembang dapat memeriksa apakah percepatan diaktifkan melalui canvas.isHardwareAccelerated(). Dengan percepatan hardware, beberapa operasi Canvas tidak didukung (misalnya, clipPath dengan area non-persegi panjang) dan dapat diabaikan atau menyebabkan kesalahan.

Canvas API untuk grafis kustom

Canvas menyediakan kumpulan metode yang kaya untuk menggambar. Semua metode bekerja dalam sistem koordinat saat ini, yang dapat diubah melalui transformasi (translate, rotate, scale, skew). Setiap metode menerima objek Paint yang menentukan warna, gaya, ketebalan garis, efek, dan anti-aliasing.

Metode CanvasTujuanParameter kunci Paint
drawCircleMenggambar lingkarancenterX, centerY, radius, paint
drawRectMenggambar persegi panjangleft, top, right, bottom, paint
drawLineMenggambar garisstartX, startY, endX, endY, paint
drawPathMenggambar kontur sembarangpath, paint
drawBitmapMenggambar gambarbitmap, srcRect, dstRect, paint
drawTextMenggambar tekstext, x, y, paint
drawArcMenggambar busur atau sektorovalRect, startAngle, sweepAngle, useCenter, paint
drawOvalMenggambar ovalovalRect, paint

Objek Paint

Paint menentukan gaya rendering: warna (setColor), ketebalan garis (setStrokeWidth), gaya isian (setStyle — FILL, STROKE, FILL_AND_STROKE), anti-aliasing (setAntiAlias), efek (setShadowLayer, setMaskFilter) dan gradien (setShader). Disarankan untuk membuat dan mengonfigurasi Paint satu kali di konstruktor View, bukan di dalam onDraw, untuk menghindari pembuatan objek dalam siklus rendering.

Koordinat dan transformasi

Canvas menggunakan sistem koordinat di mana sumbu X mengarah ke kanan dan sumbu Y ke bawah. Titik asal (0, 0) adalah sudut kiri atas View. Sebelum memanggil metode draw, pengembang dapat mengubah sistem koordinat melalui canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py). Semua operasi menggambar selanjutnya akan dijalankan dalam sistem yang telah ditransformasi.

Kinerja onDraw

onDraw dijalankan di thread UI utama, dan durasinya secara langsung memengaruhi frame rate (fps). Untuk mempertahankan 60 fps, metode onDraw harus selesai dalam waktu tidak lebih dari 16 milidetik. Perlambatan apa pun menyebabkan frame terlewat (jank), yang secara visual terlihat sebagai animasi tersendat atau keterlambatan saat scrolling.

Aturan onDraw yang berkinerja tinggi

Aturan utama optimasi onDraw meliputi: 1) jangan membuat objek di dalam onDraw — semua Paint, Path, Rect harus menjadi bidang kelas; 2) jangan mengalokasikan memori (new) — ini memicu garbage collection (GC) dan frame terlewat; 3) cache operasi kompleks di Bitmap melalui Bitmap.createBitmap dan gambar Bitmap yang sudah siap; 4) jangan melakukan operasi input-output atau memuat sumber daya.

Menggunakan clipRect untuk optimasi

clipRect membatasi area menggambar ke persegi panjang yang ditentukan. Digunakan agar Canvas tidak membuang waktu merender piksel di luar area yang terlihat. Sangat efektif saat scrolling daftar besar atau scaling: atur clipRect ke area yang terlihat (dirty rect), dan Canvas hanya akan menggambar apa yang terlihat.

Layer — menyimpan dan memulihkan

canvas.save() menyimpan status Canvas saat ini (transformasi dan clip) ke dalam stack. canvas.restore() memulihkan status terakhir yang disimpan. Ini diperlukan untuk transformasi sementara: simpan status, terapkan translate/rotate, gambar, lalu pulihkan. save dan restore ringan dan tidak memengaruhi kinerja jika digunakan secara wajar (kurang dari 10–15 level nesting).

invalidate dan postInvalidate

invalidate() — adalah metode View yang memberi tahu sistem bahwa konten View sudah usang dan perlu digambar ulang. Pemanggilan invalidate memulai siklus draw baru di mana onDraw akan dipanggil. invalidate hanya boleh dipanggil dari thread UI (main thread). Untuk pemanggilan dari thread latar belakang, digunakan postInvalidate.

postInvalidate() — versi invalidate yang thread-safe, yang mengirim permintaan penggambaran ulang ke antrian thread utama melalui Handler. Digunakan dalam tugas latar belakang ketika View perlu diperbarui setelah selesai memuat data atau melakukan perhitungan. Dikombinasikan dengan runOnUiThread untuk sinkronisasi dengan UI.

Untuk penggambaran ulang sebagian digunakan invalidate(Rect dirty) atau invalidate(int l, int t, int r, int b). Ini memberi tahu sistem bahwa hanya area yang ditentukan yang berubah, bukan seluruh View. Android mengoptimalkan rendering dengan menggambar ulang hanya dirty rect, yang secara signifikan meningkatkan kinerja pada animasi dengan pembaruan parsial.

Contoh kode di Kotlin

Mari kita lihat contoh praktis override onDraw untuk membuat View kustom di Android dengan Kotlin.

View kustom — progres melingkar

Contoh membuat indikator progres melingkar dengan pengisian animasi. onDraw menggambar dua lingkaran: latar belakang abu-abu dan isian berwarna, yang busurnya ditentukan oleh progres saat ini. Pemanggilan invalidate di setProgress memastikan penggambaran ulang saat nilai berubah.

kotlin
class CircularProgressView
    @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    private val bgPaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 12f
        color = Color.parseColor("#E0E0E0")
        isAntiAlias = true
    }

    private val progressPaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 12f
        color = Color.BLUE
        isAntiAlias = true
        strokeCap = Paint.Cap.ROUND
    }

    var progress: Float = 0f
        set(value) {
            field = value.coerceIn(0f, 1f)
            invalidate()
        }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val size = minOf(width, height) - 24f
        val oval = RectF(12f, 12f,
                          12f + size, 12f + size)

        canvas.drawArc(oval, 270f, 360f, false, bgPaint)
        canvas.drawArc(oval, 270f,
                        progress * 360f,
                        false, progressPaint)
    }
}

View kustom — latar gradien dengan teks

Contoh menggambar persegi panjang dengan gradien dan teks di atasnya. Gradien dibuat melalui LinearGradient (Shader), dan teks melalui drawText. Kedua Paint dibuat satu kali di konstruktor, dan di onDraw hanya ukuran persegi panjang yang berubah tergantung pada lebar View saat ini.

kotlin
class GradientTextView(context: Context)
    : View(context) {

    private val shaderPaint = Paint().apply {
        isAntiAlias = true
    }

    private val textPaint = Paint().apply {
        color = Color.WHITE
        textSize = 48f
        isAntiAlias = true
        textAlign = Paint.Align.CENTER
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        val gradient = LinearGradient(
            0f, 0f, width.toFloat(), 0f,
            Color.parseColor("#FF6B35"),
            Color.parseColor("#FF0040"),
            Shader.TileMode.CLAMP
        )
        shaderPaint.shader = gradient
        canvas.drawRect(0f, 0f,
                        width.toFloat(),
                        height.toFloat(), shaderPaint)

        val xCenter = width / 2f
        val yCenter = height / 2f
        val yOffset = (textPaint.descent() +
                        textPaint.ascent()) / 2f

        canvas.drawText("Halo dari Canvas",
                      xCenter, yCenter - yOffset,
                      textPaint)
    }
}

Jam animasi menggunakan invalidate

Contoh membuat jam animasi yang memperbarui rendering setiap 1000 milidetik. postDelayed di onDraw memanggil invalidate setelah satu detik, menciptakan siklus penggambaran ulang tak terbatas. Jarum jam digambar melalui drawLine dengan panjang dan ketebalan yang berbeda.

kotlin
class AnalogClockView(context: Context)
    : View(context) {

    private val handPaint = Paint().apply {
        style = Paint.Style.STROKE
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val cx = width / 2f
        val cy = height / 2f
        val radius = minOf(cx, cy) - 20f

        val now = Calendar.getInstance()
        val hours = now.get(Calendar.HOUR) % 12
        val minutes = now.get(Calendar.MINUTE)
        val seconds = now.get(Calendar.SECOND)

        val secondAngle = Math.toRadians(
            seconds * 6f - 90f)
        handPaint.strokeWidth = 2f
        handPaint.color = Color.RED
        canvas.drawLine(cx, cy,
            cx + cos(secondAngle) * radius * 0.8f,
            cy + sin(secondAngle) * radius * 0.8f,
            handPaint)

        postDelayed({ invalidate() }, 1000)
    }
}

Pertanyaan yang sering diajukan

Bisakah onDraw dipanggil secara langsung?

Tidak, onDraw tidak boleh dipanggil secara langsung. Untuk meminta penggambaran ulang, gunakan invalidate() (dari thread UI) atau postInvalidate() (dari thread latar belakang). Sistem sendiri yang memutuskan kapan akan memanggil onDraw dan mengoptimalkan rendering dengan menggabungkan beberapa invalidate menjadi satu langkah.

Mengapa onDraw tidak dipanggil setelah invalidate?

Penyebab: View tersembunyi (setVisibility(GONE) atau INVISIBLE); View belum ditambahkan ke hierarki Window; ukuran View adalah 0 (width atau height = 0); setWillNotDraw(true) dipanggil (default true untuk ViewGroup). Periksa masing-masing poin ini saat debugging.

Seberapa sering onDraw dapat dipanggil?

Pada 60 fps, onDraw dapat dipanggil hingga 60 kali per detik. Pada 120 fps (di perangkat dengan layar 120 Hz) — hingga 120 kali. Setiap pemanggilan harus selesai dalam ~8–16 milidetik. Pada animasi aktif melalui ObjectAnimator atau ValueAnimator, frekuensi ditentukan oleh jumlah frame animasi.

Apa perbedaan antara onDraw dan dispatchDraw?

onDraw bertanggung jawab untuk merender konten View itu sendiri. dispatchDraw bertanggung jawab untuk merender View anak (di ViewGroup). dispatchDraw dipanggil setelah onDraw dan secara rekursif melintasi semua elemen anak. Untuk View biasa (bukan ViewGroup), dispatchDraw kosong.

Bisakah Canvas digunakan di luar onDraw?

Ya, Canvas dapat dibuat untuk Bitmap melalui Canvas(bitmap) dan digambar di thread mana pun. Ini digunakan untuk pra-komputasi grafis kompleks di latar belakang. Namun, Canvas yang diteruskan ke onDraw adalah milik sistem dan hanya dapat digunakan di thread UI di dalam metode onDraw.

Ringkasan

  • onDraw(Canvas) — metode kunci View untuk rendering kustom menggunakan Canvas API di Android
  • Siklus rendering terdiri dari fase measure, layout dan draw — onDraw dipanggil di fase draw
  • Canvas API mencakup metode drawCircle, drawRect, drawPath, drawBitmap, drawText dan lainnya
  • invalidate() meminta penggambaran ulang dari thread UI, postInvalidate() — dari thread latar belakang
  • Penggambaran ulang sebagian melalui invalidate(Rect) mengoptimalkan rendering dengan hanya memperbarui area dirty
  • Kinerja onDraw sangat penting: membuat objek di dalam metode menyebabkan GC dan frame terlewat
  • Percepatan hardware (sejak API 11) secara otomatis mempercepat operasi Canvas melalui GPU

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.

Diskusikan proyek

Baca juga