onDraw() — wat is het, aanroepmechanisme en het overschrijven van de methode

Auteur: IT Sectr Gepubliceerd: 2026-07-22 Leestijd: 10 min

onDraw() — is de belangrijkste methode van de klasse View in de Android SDK, verantwoordelijk voor het weergeven van de inhoud van de weergave. Het systeem roept onDraw aan bij elke update van het uiterlijk van View — bij de initiële rendering, na invalidate() of bij het wijzigen van afmetingen. Volgens de Android Developers Documentation (2026) is het overschrijven van onDraw met behulp van de Canvas API de primaire manier om aangepaste graphics te maken in Android-applicaties.

Belangrijkste punten

  • onDraw(Canvas) — View-methode aangeroepen door het systeem om inhoud op Canvas te renderen
  • invalidate() — verzoek om View opnieuw te tekenen, leidend tot aanroep van onDraw in de volgende framecyclus
  • Canvas API biedt methoden drawCircle, drawBitmap, drawText, drawPath en andere voor tekenen
  • Het Android-systeem voert rendering uit in de UI-thread, dus onDraw moet licht en snel zijn
  • Hardware acceleration versnelt automatisch rendering via GPU, vanaf Android 3.0 (API 11)

Wat is onDraw()?

onDraw(Canvas canvas) — is een protected methode van de klasse android.view.View, die wordt aangeroepen door het Android-systeem wanneer View moet worden gerenderd. De ontwikkelaar overschrijft deze methode om aangepaste weergave te implementeren: vormen, tekst, afbeeldingen, verloop, animatie. De parameter Canvas is het grafische oppervlak waarop alle tekenbewerkingen worden uitgevoerd.

De handtekening van de methode is eenvoudig: override fun onDraw(canvas: Canvas). Binnen deze methode mogen geen nieuwe objecten worden gemaakt (om GC-belasting te voorkomen), lange bewerkingen worden uitgevoerd of met het netwerk worden gewerkt. View bevat ook de methode onDraw in zijn levenscyclus tussen onLayout (positieberekening) en dispatchDraw (weergave van onderliggende elementen).

Bij overerving van View is het overschrijven van onDraw verplicht voor het tonen van inhoud — anders blijft View leeg. Bij overerving van bestaande subklassen (TextView, ImageView, Button) is het overschrijven van onDraw optioneel en wordt gebruikt om extra graphics bovenop de standaardinhoud toe te voegen.

View-renderingcyclus

Android voert de weergave van View uit in een strikt gedefinieerde volgorde, aangeroepen vanuit de hoofdthread (UI-thread). De volledige cyclus bestaat uit drie fasen: measure (meten van afmetingen), layout (berekenen van posities) en draw (tekenen). onDraw maakt deel uit van de draw-fase en wordt aangeroepen nadat de afmetingen en positie van View zijn bepaald.

Draw-fase: dispatchDraw en onDraw

draw(Canvas canvas) — is de publieke methode van View die onDraw en dispatchDraw aanroept. De methode draw is niet bedoeld om te worden overschreven — in plaats daarvan wordt onDraw overschreven. Na uitvoering van onDraw voor de huidige View wordt dispatchDraw aangeroepen, die recursief draw aanroept voor alle onderliggende Views (als de huidige View een ViewGroup-container is).

Wanneer het systeem onDraw aanroept

onDraw wordt aangeroepen onder de volgende voorwaarden: 1) View wordt voor het eerst zichtbaar (na setVisibility(VISIBLE)); 2) de applicatie roept invalidate() aan voor deze View of de ouder ervan; 3) de grootte van View verandert (nieuwe layout); 4) de animatie die aan View is gekoppeld verandert (via ValueAnimator of ObjectAnimator); 5) de status van View verandert (pressed, focused, enabled).

Hardwareversnelling

Vanaf Android 3.0 (API 11) worden de meeste Canvas-bewerkingen uitgevoerd met hardwareversnelling via GPU. De ontwikkelaar kan controleren of versnelling is ingeschakeld via canvas.isHardwareAccelerated(). Bij hardwareversnelling worden sommige Canvas-bewerkingen niet ondersteund (bijv. clipPath met een niet-rechthoekig gebied) en kunnen worden genegeerd of fouten veroorzaken.

Canvas API voor aangepaste graphics

Canvas biedt een rijke set methoden voor tekenen. Alle methoden werken in het huidige coördinatensysteem, dat kan worden gewijzigd via transformaties (translate, rotate, scale, skew). Elke methode accepteert een Paint-object dat de kleur, stijl, lijndikte, effecten en anti-aliasing definieert.

Canvas-methodeDoelBelangrijkste Paint-parameters
drawCircleCirkel tekenencenterX, centerY, radius, paint
drawRectRechthoek tekenenleft, top, right, bottom, paint
drawLineLijn tekenenstartX, startY, endX, endY, paint
drawPathWillekeurige contour tekenenpath, paint
drawBitmapAfbeelding tekenenbitmap, srcRect, dstRect, paint
drawTextTekst tekenentext, x, y, paint
drawArcBoog of sector tekenenovalRect, startAngle, sweepAngle, useCenter, paint
drawOvalOvaal tekenenovalRect, paint

Paint-object

Paint definieert de tekenstijl: kleur (setColor), lijndikte (setStrokeWidth), vulstijl (setStyle — FILL, STROKE, FILL_AND_STROKE), anti-aliasing (setAntiAlias), effecten (setShadowLayer, setMaskFilter) en verlopen (setShader). Het wordt aanbevolen om Paint eenmalig in de constructor van View te maken en configureren, niet binnen onDraw, om het maken van objecten in de weergavecyclus te voorkomen.

Coördinaten en transformaties

Canvas gebruikt een coördinatensysteem waarbij de X-as naar rechts is gericht en de Y-as naar beneden. De oorsprong (0, 0) is de linkerbovenhoek van View. Voordat de draw-methoden worden aangeroepen, kan de ontwikkelaar het coördinatensysteem wijzigen via canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py). Alle volgende tekenbewerkingen worden uitgevoerd in het getransformeerde systeem.

Prestaties van onDraw

onDraw wordt uitgevoerd in de hoofd-UI-thread en de duur ervan beïnvloedt direct de framerate (fps). Om 60 fps te behouden, moet de methode onDraw binnen maximaal 16 milliseconden worden voltooid. Elke vertraging leidt tot frameverlies (jank), wat visueel wordt waargenomen als haperende animatie of vertraging bij scrollen.

Regels voor performante onDraw

Basisregels voor optimalisatie van onDraw omvatten: 1) maak geen objecten binnen onDraw — alle Paint, Path, Rect moeten velden van de klasse zijn; 2) wijs geen geheugen toe (new) — dit activeert garbage collection (GC) en frameverlies; 3) cache complexe bewerkingen in Bitmap via Bitmap.createBitmap en teken de voorbereide Bitmap; 4) voer geen invoer-uitvoerbewerkingen of het laden van bronnen uit.

clipRect gebruiken voor optimalisatie

clipRect beperkt het tekengebied tot een opgegeven rechthoek. Wordt gebruikt zodat Canvas geen tijd verspilt aan het renderen van pixels buiten het zichtbare gebied. Bijzonder effectief bij het scrollen van grote lijsten of schalen: stel clipRect in op het zichtbare gebied (dirty rect), en Canvas tekent alleen wat zichtbaar is.

Layer — opslaan en herstellen

canvas.save() slaat de huidige status van Canvas (transformatie en clip) op in een stack. canvas.restore() herstelt de laatst opgeslagen status. Dit is nodig voor tijdelijke transformaties: status opslaan, translate/rotate toepassen, tekenen, vervolgens herstellen. save en restore zijn lichtgewicht en beïnvloeden de prestaties niet bij redelijk gebruik (minder dan 10–15 niveaus van nesting).

invalidate en postInvalidate

invalidate() — is de View-methode die het systeem informeert dat de inhoud van View verouderd is en opnieuw moet worden getekend. Aanroep van invalidate start een nieuwe draw-cyclus waarin onDraw wordt aangeroepen. invalidate mag alleen vanuit de UI-thread (main thread) worden aangeroepen. Voor aanroep vanuit een achtergrondthread wordt postInvalidate gebruikt.

postInvalidate() — de thread-veilige versie van invalidate, die een verzoek tot opnieuw tekenen naar de wachtrij van de hoofdthread stuurt via Handler. Wordt gebruikt in achtergrondtaken wanneer View moet worden bijgewerkt na het laden van gegevens of berekeningen. Wordt gecombineerd met runOnUiThread voor synchronisatie met de UI.

Voor gedeeltelijk opnieuw tekenen wordt invalidate(Rect dirty) of invalidate(int l, int t, int r, int b) gebruikt. Dit geeft aan het systeem aan dat alleen het opgegeven gebied is gewijzigd, niet de hele View. Android optimaliseert rendering door alleen de dirty rect opnieuw te tekenen, wat de prestaties aanzienlijk verbetert bij animaties met gedeeltelijke updates.

Codevoorbeelden in Kotlin

Laten we praktische voorbeelden bekijken van het overschrijven van onDraw voor het maken van aangepaste Views in Android met Kotlin.

Aangepaste View — cirkelvormige voortgang

Het voorbeeld creëert een cirkelvormige voortgangsindicator met geanimeerde vulling. onDraw tekent twee cirkels: een grijze achtergrond en een gekleurde gevulde, waarvan de boog wordt bepaald door de huidige voortgang. Aanroep van invalidate in setProgress zorgt voor opnieuw tekenen bij wijziging van de waarde.

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

Aangepaste View — verloopachtergrond met tekst

Het voorbeeld tekent een rechthoek met verloop en tekst erbovenop. Het verloop wordt gemaakt via LinearGradient (Shader) en de tekst via drawText. Beide Paint-objecten worden eenmalig in de constructor gemaakt, en in onDraw wordt alleen de grootte van de rechthoek gewijzigd op basis van de huidige breedte van 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("Hallo van Canvas",
                      xCenter, yCenter - yOffset,
                      textPaint)
    }
}

Geanimeerde klok met invalidate

Het voorbeeld creëert een geanimeerde klok die de weergave elke 1000 milliseconden bijwerkt. postDelayed in onDraw roept invalidate aan na een seconde, waardoor een oneindige cyclus van opnieuw tekenen ontstaat. De wijzers van de klok worden getekend via drawLine met verschillende lengte en dikte.

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

Veelgestelde vragen

Kan onDraw direct worden aangeroepen?

Nee, onDraw mag niet direct worden aangeroepen. Gebruik voor een verzoek tot opnieuw tekenen invalidate() (vanuit de UI-thread) of postInvalidate() (vanuit de achtergrondthread). Het systeem beslist zelf wanneer onDraw wordt aangeroepen en optimaliseert rendering door meerdere invalidate-aanroepen in één doorgang te combineren.

Waarom wordt onDraw niet aangeroepen na invalidate?

Oorzaken: View is verborgen (setVisibility(GONE) of INVISIBLE); View is niet toegevoegd aan de Window-hiërarchie; View-grootte is 0 (width of height = 0); setWillNotDraw(true) wordt aangeroepen (standaard true voor ViewGroup). Controleer elk van deze punten bij het debuggen.

Hoe vaak kan onDraw worden aangeroepen?

Bij 60 fps kan onDraw tot 60 keer per seconde worden aangeroepen. Bij 120 fps (op apparaten met 120 Hz-schermen) — tot 120 keer. Elke aanroep moet binnen ~8–16 milliseconden worden voltooid. Bij actieve animaties via ObjectAnimator of ValueAnimator wordt de frequentie bepaald door het aantal animatieframes.

Wat is het verschil tussen onDraw en dispatchDraw?

onDraw is verantwoordelijk voor het weergeven van de inhoud van View zelf. dispatchDraw is verantwoordelijk voor het weergeven van onderliggende Views (in ViewGroup). dispatchDraw wordt aangeroepen na onDraw en doorloopt recursief alle onderliggende elementen. Voor een gewone View (geen ViewGroup) is dispatchDraw leeg.

Kan Canvas buiten onDraw worden gebruikt?

Ja, Canvas kan worden gemaakt voor Bitmap via Canvas(bitmap) en er kan in elke thread op worden getekend. Dit wordt gebruikt voor het vooraf berekenen van complexe graphics op de achtergrond. Echter, de Canvas die in onDraw wordt doorgegeven, is eigendom van het systeem en mag alleen in de UI-thread binnen de methode onDraw worden gebruikt.

Samenvatting

  • onDraw(Canvas) — belangrijkste View-methode voor aangepaste weergave met Canvas API in Android
  • Weergavecyclus bestaat uit de fasen measure, layout en draw — onDraw wordt in de draw-fase aangeroepen
  • Canvas API omvat methoden drawCircle, drawRect, drawPath, drawBitmap, drawText en andere
  • invalidate() vraagt opnieuw tekenen vanuit de UI-thread, postInvalidate() — vanuit de achtergrondthread
  • Gedeeltelijk opnieuw tekenen via invalidate(Rect) optimaliseert rendering door alleen het dirty-gebied bij te werken
  • Prestaties van onDraw zijn kritiek: het maken van objecten binnen de methode veroorzaakt GC en frameverlies
  • Hardwareversnelling (vanaf API 11) versnelt automatisch Canvas-bewerkingen via GPU

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project