onDraw() — ano ito, mekanismo ng pagtawag at pag-override ng metodo

May-akda: IT Sectr Nai-publish: 2026-07-22 Oras ng pagbabasa: 10 min

onDraw() — ay ang pangunahing metodo ng klase View sa Android SDK, na responsable sa pag-render ng nilalaman ng view. Tinatawag ng sistema ang onDraw sa bawat pag-update ng itsura ng View — sa paunang rendering, pagkatapos ng invalidate() o kapag nagbago ang mga sukat. Ayon sa Android Developers Documentation (2026), ang pag-override ng onDraw gamit ang Canvas API ay ang pangunahing paraan ng paggawa ng custom na graphics sa Android applications.

Mga pangunahing punto

  • onDraw(Canvas) — metodo ng View na tinatawag ng sistema para i-render ang nilalaman sa Canvas
  • invalidate() — kahilingan na i-redraw ang View, na nagdudulot ng pagtawag ng onDraw sa susunod na frame cycle
  • Canvas API ay nagbibigay ng mga metodong drawCircle, drawBitmap, drawText, drawPath at iba pa para sa pagguhit
  • Ang Android system ay nagsasagawa ng rendering sa UI thread, kaya ang onDraw ay dapat na magaan at mabilis
  • Hardware acceleration ay awtomatikong pinapabilis ang rendering sa pamamagitan ng GPU, simula sa Android 3.0 (API 11)

Ano ang onDraw()?

onDraw(Canvas canvas) — ay isang protected metodo ng klase android.view.View, na tinatawag ng Android system kapag ang View ay kailangang i-render. Ino-override ng developer ang metodong ito upang ipatupad ang custom na rendering: mga hugis, teksto, larawan, gradient, animation. Ang parameter na Canvas ay ang graphical surface kung saan isinasagawa ang lahat ng operasyon sa pagguhit.

Ang signature ng metodo ay simple: override fun onDraw(canvas: Canvas). Sa loob ng metodong ito ay hindi maaaring gumawa ng bagong object (upang maiwasan ang GC load), magsagawa ng mahabang operasyon o makipag-ugnayan sa network. Ang View ay naglalaman din ng metodo onDraw sa lifecycle nito sa pagitan ng onLayout (pagkalkula ng posisyon) at dispatchDraw (rendering ng mga child element).

Kapag nagmana mula sa View, ang pag-override ng onDraw ay kinakailangan upang magpakita ng anumang nilalaman — kung hindi, ang View ay magiging walang laman. Kapag nagmana mula sa umiiral na mga subklase (TextView, ImageView, Button), ang pag-override ng onDraw ay opsyonal at ginagamit upang magdagdag ng karagdagang graphics sa ibabaw ng karaniwang nilalaman.

Rendering cycle ng View

Android ay nagsasagawa ng rendering ng View sa isang mahigpit na tinukoy na pagkakasunod-sunod, na tinatawag mula sa pangunahing thread (UI thread). Ang buong cycle ay binubuo ng tatlong phase: measure (pagsukat ng mga sukat), layout (pagkalkula ng mga posisyon) at draw (rendering). Ang onDraw ay bahagi ng draw phase at tinatawag pagkatapos matukoy ang mga sukat at posisyon ng View.

Draw phase: dispatchDraw at onDraw

draw(Canvas canvas) — ay ang public metodo ng View na tumatawag ng onDraw at dispatchDraw. Ang metodo draw ay hindi nilayon na i-override — sa halip, ang onDraw ang ino-override. Pagkatapos ng execution ng onDraw para sa kasalukuyang View, tinatawag ang dispatchDraw, na recursively tumatawag ng draw para sa lahat ng child View (kung ang kasalukuyang View ay isang ViewGroup container).

Kailan tinatawag ng sistema ang onDraw

onDraw ay tinatawag sa mga sumusunod na kondisyon: 1) View ay nagiging visible sa unang pagkakataon (pagkatapos ng setVisibility(VISIBLE)); 2) ang application ay tumatawag ng invalidate() para sa View na ito o sa magulang nito; 3) nagbabago ang laki ng View (bagong layout); 4) nagbabago ang animation na nauugnay sa View (sa pamamagitan ng ValueAnimator o ObjectAnimator); 5) nagbabago ang estado ng View (pressed, focused, enabled).

Hardware acceleration

Mula sa Android 3.0 (API 11), karamihan sa mga Canvas operations ay isinasagawa gamit ang hardware acceleration sa pamamagitan ng GPU. Maaaring suriin ng developer kung naka-enable ang acceleration sa pamamagitan ng canvas.isHardwareAccelerated(). Sa hardware acceleration, ang ilang Canvas operations ay hindi suportado (hal., clipPath na may non-rectangular na lugar) at maaaring balewalain o magdulot ng error.

Canvas API para sa custom na graphics

Canvas ay nagbibigay ng mayamang set ng mga metodo para sa pagguhit. Lahat ng metodo ay gumagana sa kasalukuyang coordinate system, na maaaring baguhin sa pamamagitan ng mga transformasyon (translate, rotate, scale, skew). Bawat metodo ay tumatanggap ng Paint object na tumutukoy sa kulay, style, kapal ng linya, mga epekto at anti-aliasing.

Canvas methodLayuninMga pangunahing parameter ng Paint
drawCirclePagguhit ng bilogcenterX, centerY, radius, paint
drawRectPagguhit ng parihabaleft, top, right, bottom, paint
drawLinePagguhit ng linyastartX, startY, endX, endY, paint
drawPathPagguhit ng arbitraryong contourpath, paint
drawBitmapPagguhit ng larawanbitmap, srcRect, dstRect, paint
drawTextPagguhit ng tekstotext, x, y, paint
drawArcPagguhit ng arko o sektorovalRect, startAngle, sweepAngle, useCenter, paint
drawOvalPagguhit ng obaloovalRect, paint

Paint object

Paint ay tumutukoy sa style ng rendering: kulay (setColor), kapal ng linya (setStrokeWidth), style ng fill (setStyle — FILL, STROKE, FILL_AND_STROKE), anti-aliasing (setAntiAlias), mga epekto (setShadowLayer, setMaskFilter) at mga gradient (setShader). Inirerekomenda na gawin at i-configure ang Paint nang isang beses sa constructor ng View, hindi sa loob ng onDraw, upang maiwasan ang paggawa ng object sa rendering cycle.

Coordinate at transformasyon

Canvas ay gumagamit ng coordinate system kung saan ang X axis ay nakaturo sa kanan, at ang Y axis ay pababa. Ang pinagmulan (0, 0) ay ang kaliwang itaas na sulok ng View. Bago tumawag ng draw methods, maaaring baguhin ng developer ang coordinate system sa pamamagitan ng canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py). Lahat ng kasunod na operasyon sa pagguhit ay isasagawa sa transformed system.

Pagganap ng onDraw

onDraw ay isinasagawa sa pangunahing UI thread, at ang tagal nito ay direktang nakakaapekto sa frame rate (fps). Upang mapanatili ang 60 fps, ang metodo onDraw ay dapat matapos sa loob ng hindi hihigit sa 16 millisecond. Anumang pagbagal ay nagdudulot ng paglaktaw ng frame (jank), na biswal na nakikita bilang pag-stutter ng animation o pagkaantala sa scrolling.

Mga tuntunin para sa performant na onDraw

Mga pangunahing tuntunin ng pag-optimize ng onDraw ay kinabibilangan ng: 1) huwag gumawa ng object sa loob ng onDraw — lahat ng Paint, Path, Rect ay dapat na field ng klase; 2) huwag mag-allocate ng memory (new) — ito ay nagti-trigger ng garbage collection (GC) at paglaktaw ng frame; 3) i-cache ang mga kumplikadong operasyon sa Bitmap sa pamamagitan ng Bitmap.createBitmap at iguhit ang handa na Bitmap; 4) huwag magsagawa ng input-output operations o pag-load ng resources.

Paggamit ng clipRect para sa pag-optimize

clipRect ay naglilimita sa lugar ng pagguhit sa isang tinukoy na parihaba. Ginagamit upang hindi mag-aksaya ng oras ang Canvas sa pag-render ng pixels sa labas ng nakikitang lugar. Lalo na epektibo sa scrolling ng malalaking listahan o scaling: itakda ang clipRect sa nakikitang lugar (dirty rect), at ang Canvas ay iguguhit lamang ang nakikita.

Layer — pag-save at pag-restore

canvas.save() ay nagse-save ng kasalukuyang estado ng Canvas (transformasyon at clip) sa stack. canvas.restore() ay nagre-restore ng huling na-save na estado. Ito ay kinakailangan para sa pansamantalang transformasyon: i-save ang estado, ilapat ang translate/rotate, iguhit, pagkatapos ay i-restore. Ang save at restore ay magaan at hindi nakakaapekto sa pagganap kung gagamitin nang makatwiran (mas mababa sa 10–15 antas ng nesting).

invalidate at postInvalidate

invalidate() — ay ang metodo ng View na nagpapaalam sa sistema na ang nilalaman ng View ay lipas na at kailangang i-redraw. Ang pagtawag ng invalidate ay nagpapasimula ng bagong draw cycle kung saan tatawagin ang onDraw. Ang invalidate ay dapat tawagin lamang mula sa UI thread (main thread). Para sa pagtawag mula sa background thread, ginagamit ang postInvalidate.

postInvalidate() — ang thread-safe na bersyon ng invalidate, na nagpapadala ng kahilingan para i-redraw sa queue ng pangunahing thread sa pamamagitan ng Handler. Ginagamit sa mga background task kapag kailangang i-update ang View pagkatapos ng pagkarga ng data o pagkalkula. Pinagsasama sa runOnUiThread para sa pag-sync sa UI.

Para sa partial na pag-redraw ginagamit ang invalidate(Rect dirty) o invalidate(int l, int t, int r, int b). Ito ay nagpapahiwatig sa sistema na ang tinukoy na lugar lamang ang nagbago, hindi ang buong View. Ino-optimize ng Android ang rendering sa pamamagitan ng pag-redraw lamang ng dirty rect, na makabuluhang nagpapabuti ng pagganap sa mga animation na may bahagyang pag-update.

Mga halimbawa ng code sa Kotlin

Tingnan natin ang mga praktikal na halimbawa ng pag-override ng onDraw para gumawa ng custom na Views sa Android gamit ang Kotlin.

Custom na View — circular na progreso

Ang halimbawa ay gumagawa ng circular na indicator ng progreso na may animated na pagpuno. Ang onDraw ay gumuhit ng dalawang bilog: isang gray na background at isang may kulay na puno, na ang arko ay tinutukoy ng kasalukuyang progreso. Ang pagtawag ng invalidate sa setProgress ay tinitiyak ang pag-redraw kapag nagbago ang halaga.

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)
    }
}

Custom na View — gradient background na may teksto

Ang halimbawa ay gumuhit ng parihaba na may gradient at teksto sa ibabaw nito. Ang gradient ay ginagawa sa pamamagitan ng LinearGradient (Shader), at ang teksto sa pamamagitan ng drawText. Ang parehong Paint ay ginawa nang isang beses sa constructor, at sa onDraw ay binabago lamang ang laki ng parihaba batay sa kasalukuyang lapad ng View.

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("Kumusta mula sa Canvas",
                      xCenter, yCenter - yOffset,
                      textPaint)
    }
}

Animated na orasan gamit ang invalidate

Ang halimbawa ay gumagawa ng animated na orasan na nag-a-update ng rendering bawat 1000 millisecond. Ang postDelayed sa onDraw ay tumatawag ng invalidate pagkatapos ng isang segundo, na lumilikha ng walang katapusang cycle ng pag-redraw. Ang mga kamay ng orasan ay iginuguhit sa pamamagitan ng drawLine na may iba't ibang haba at kapal.

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)
    }
}

Mga madalas itanong

Maaari bang direktang tawagin ang onDraw?

Hindi, hindi dapat direktang tawagin ang onDraw. Para sa kahilingan ng pag-redraw, gamitin ang invalidate() (mula sa UI thread) o postInvalidate() (mula sa background thread). Ang sistema mismo ang nagpapasya kung kailan tatawagin ang onDraw at ino-optimize ang rendering sa pamamagitan ng pagsasama-sama ng maraming invalidate sa isang pass.

Bakit hindi tinatawag ang onDraw pagkatapos ng invalidate?

Mga dahilan: View ay nakatago (setVisibility(GONE) o INVISIBLE); View ay hindi naidagdag sa hierarchy ng Window; laki ng View ay 0 (width o height = 0); tinatawag ang setWillNotDraw(true) (default true para sa ViewGroup). Suriin ang bawat isa sa mga puntong ito habang nagde-debug.

Gaano kadalas maaaring tawagin ang onDraw?

Sa 60 fps, ang onDraw ay maaaring tawagin hanggang 60 beses bawat segundo. Sa 120 fps (sa mga device na may 120 Hz display) — hanggang 120 beses. Bawat pagtawag ay dapat matapos sa ~8–16 millisecond. Sa mga aktibong animation sa pamamagitan ng ObjectAnimator o ValueAnimator, ang frequency ay tinutukoy ng bilang ng animation frames.

Ano ang pagkakaiba sa pagitan ng onDraw at dispatchDraw?

onDraw ay responsable para sa pag-render ng nilalaman ng View mismo. dispatchDraw ay responsable para sa pag-render ng mga child View (sa ViewGroup). Ang dispatchDraw ay tinatawag pagkatapos ng onDraw at recursively dumadaan sa lahat ng child elements. Para sa isang ordinaryong View (hindi ViewGroup), ang dispatchDraw ay walang laman.

Maaari bang gamitin ang Canvas sa labas ng onDraw?

Oo, ang Canvas ay maaaring gawin para sa Bitmap sa pamamagitan ng Canvas(bitmap) at gumuhit dito sa anumang thread. Ito ay ginagamit para sa pre-computation ng kumplikadong graphics sa background. Gayunpaman, ang Canvas na ipinapasa sa onDraw ay pag-aari ng sistema at maaari lamang gamitin sa UI thread sa loob ng metodo onDraw.

Buod

  • onDraw(Canvas) — pangunahing metodo ng View para sa custom na rendering gamit ang Canvas API sa Android
  • Rendering cycle ay binubuo ng mga phase na measure, layout at draw — onDraw ay tinatawag sa draw phase
  • Canvas API ay may kasamang mga metodong drawCircle, drawRect, drawPath, drawBitmap, drawText at iba pa
  • invalidate() ay humihiling ng pag-redraw mula sa UI thread, postInvalidate() — mula sa background thread
  • Partial na pag-redraw sa pamamagitan ng invalidate(Rect) ay nag-o-optimize ng rendering sa pamamagitan ng pag-update lamang ng dirty area
  • Pagganap ng onDraw ay kritikal: ang paggawa ng object sa loob ng metodo ay nagdudulot ng GC at paglaktaw ng frame
  • Hardware acceleration (mula API 11) ay awtomatikong nagpapabilis ng Canvas operations sa pamamagitan ng GPU

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din