onDraw() — was es ist, Aufrufmechanismus und Methodenüberschreibung

Autor: IT Sectr Veröffentlicht: 2026-07-22 Lesezeit: 10 Min.

onDraw() ist eine Schlüsselmethode der View-Klasse im Android SDK, die für das Zeichnen des Inhalts einer Ansicht verantwortlich ist. Das System ruft onDraw bei jeder Aktualisierung des Erscheinungsbilds der View auf — beim ersten Rendern, nach invalidate() oder bei Größenänderungen. Laut der Android Developers Documentation (2026) ist das Überschreiben von onDraw mit der Canvas API die primäre Möglichkeit, benutzerdefinierte Grafiken in Android-Anwendungen zu erstellen.

Das Wichtigste

  • onDraw(Canvas) — eine View-Methode, die vom System aufgerufen wird, um Inhalte auf der Canvas zu zeichnen
  • invalidate() — eine Anforderung zur Neuzeichnung der View, die zum Aufruf von onDraw im nächsten Frame-Zyklus führt
  • Canvas API stellt die Methoden drawCircle, drawBitmap, drawText, drawPath und andere zum Zeichnen bereit
  • Das Android-System führt das Zeichnen im UI-Thread aus, daher sollte onDraw leicht und schnell sein
  • Hardware acceleration beschleunigt das Zeichnen automatisch über die GPU, ab Android 3.0 (API 11)

Was ist onDraw()?

onDraw(Canvas canvas) ist eine protected-Methode der Klasse android.view.View, die vom Android-System aufgerufen wird, wenn eine View gezeichnet werden muss. Der Entwickler überschreibt diese Methode, um benutzerdefinierte Zeichnungen zu implementieren: Formen, Text, Bilder, Verläufe, Animationen. Der Canvas-Parameter ist eine grafische Oberfläche, auf der alle Zeichenoperationen ausgeführt werden.

Die Methodensignatur ist einfach: override fun onDraw(canvas: Canvas). Innerhalb dieser Methode sollten keine neuen Objekte erstellt (um GC-Überlastung zu vermeiden), keine langen Operationen ausgeführt oder Netzwerkzugriffe getätigt werden. View enthält die onDraw-Methode in ihrem Lebenszyklus zwischen onLayout (Positionsberechnung) und dispatchDraw (Zeichnen von Kindelementen).

Beim Erben von View ist das Überschreiben von onDraw für die Anzeige jeglichen Inhalts erforderlich — andernfalls bleibt die View leer. Beim Erben von vorhandenen Unterklassen (TextView, ImageView, Button) ist das Überschreiben von onDraw optional und wird verwendet, um zusätzliche Grafiken über den Standardinhalt zu legen.

View-Zeichenzyklus

Android führt das Zeichnen der View in einer streng definierten Reihenfolge aus, die vom Hauptthread (UI-Thread) aufgerufen wird. Der vollständige Zyklus besteht aus drei Phasen: measure (Maßberechnung), layout (Positionsberechnung) und draw (Rendering). onDraw ist Teil der draw-Phase und wird aufgerufen, nachdem die Maße und Position der View bereits bestimmt wurden.

Draw-Phase: dispatchDraw und onDraw

draw(Canvas canvas) ist eine öffentliche Methode von View, die onDraw und dispatchDraw aufruft. Die draw-Methode ist nicht zum Überschreiben gedacht — stattdessen wird onDraw überschrieben. Nach der Ausführung von onDraw für die aktuelle View wird dispatchDraw aufgerufen, das rekursiv draw für alle untergeordneten Views aufruft (wenn die aktuelle View ein ViewGroup-Container ist).

Wann das System onDraw aufruft

onDraw wird unter folgenden Bedingungen aufgerufen: 1) die View wird zum ersten Mal sichtbar (nach setVisibility(VISIBLE)); 2) die App ruft invalidate() für diese View oder ihr Eltern-Element auf; 3) die Größe der View ändert sich (neues Layout); 4) eine mit der View verbundene Animation ändert sich (via ValueAnimator oder ObjectAnimator); 5) der Zustand der View ändert sich (pressed, focused, enabled).

Hardwarebeschleunigung

Seit Android 3.0 (API 11) werden die meisten Canvas-Operationen hardwarebeschleunigt über die GPU ausgeführt. Der Entwickler kann über canvas.isHardwareAccelerated() überprüfen, ob die Beschleunigung aktiviert ist. Bei Hardwarebeschleunigung werden einige Canvas-Operationen nicht unterstützt (z.B. clipPath mit einem nicht-rechteckigen Bereich) und können ignoriert werden oder Fehler verursachen.

Canvas API für benutzerdefinierte Grafiken

Canvas bietet eine umfangreiche Sammlung von Zeichenmethoden. Alle Methoden arbeiten im aktuellen Koordinatensystem, das durch Transformationen (translate, rotate, scale, skew) geändert werden kann. Jede Methode akzeptiert ein Paint-Objekt, das Farbe, Stil, Linienstärke, Effekte und Anti-Aliasing definiert.

Canvas-MethodeZweckWichtige Paint-Parameter
drawCircleKreis zeichnencenterX, centerY, radius, paint
drawRectRechteck zeichnenleft, top, right, bottom, paint
drawLineLinie zeichnenstartX, startY, endX, endY, paint
drawPathBeliebigen Pfad zeichnenpath, paint
drawBitmapBitmap-Bild zeichnenbitmap, srcRect, dstRect, paint
drawTextText zeichnentext, x, y, paint
drawArcBogen oder Sektor zeichnenovalRect, startAngle, sweepAngle, useCenter, paint
drawOvalOval zeichnenovalRect, paint

Das Paint-Objekt

Paint definiert den Zeichenstil: Farbe (setColor), Linienstärke (setStrokeWidth), Füllstil (setStyle — FILL, STROKE, FILL_AND_STROKE), Anti-Aliasing (setAntiAlias), Effekte (setShadowLayer, setMaskFilter) und Verläufe (setShader). Es wird empfohlen, Paint einmal im View-Konstruktor zu erstellen und zu konfigurieren, nicht innerhalb von onDraw, um die Objekterstellung in der Zeichenschleife zu vermeiden.

Koordinaten und Transformationen

Canvas verwendet ein Koordinatensystem, bei dem die X-Achse nach rechts und die Y-Achse nach unten zeigt. Der Ursprung (0, 0) ist die obere linke Ecke der View. Vor dem Aufruf von Zeichenmethoden kann der Entwickler das Koordinatensystem über canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py) ändern. Alle nachfolgenden Zeichenoperationen werden im transformierten System ausgeführt.

onDraw-Leistung

onDraw wird im Haupt-UI-Thread ausgeführt, und seine Dauer wirkt sich direkt auf die Bildrate (fps) aus. Um 60 fps zu halten, muss die onDraw-Methode innerhalb von 16 Millisekunden abgeschlossen sein. Jede Verlangsamung führt zu Bildaussetzern (Jank), die visuell als Ruckeln der Animation oder Verzögerung beim Scrollen wahrgenommen werden.

Leistungsregeln für onDraw

Wichtige Regeln zur Optimierung von onDraw: 1) Keine Objekte innerhalb von onDraw erstellen — alle Paint-, Path- und Rect-Objekte sollten Klassenfelder sein; 2) Keinen Speicher allozieren (new) — dies löst Garbage Collection (GC) und Frame-Drops aus; 3) Komplexe Operationen über Bitmap.createBitmap in einer Bitmap zwischenspeichern und die vorbereitete Bitmap zeichnen; 4) Keine E/A-Operationen oder Ressourcen laden.

Verwendung von clipRect zur Optimierung

clipRect schränkt den Zeichenbereich auf ein bestimmtes Rechteck ein. Es wird verwendet, um zu verhindern, dass Canvas Zeit damit verbringt, Pixel außerhalb des sichtbaren Bereichs zu zeichnen. Besonders effektiv beim Scrollen großer Listen oder beim Zoomen: Setzen Sie clipRect auf den sichtbaren Bereich (dirty rect), und Canvas zeichnet nur das, was sichtbar ist.

Layer — Speichern und Wiederherstellen

canvas.save() speichert den aktuellen Canvas-Zustand (Transformation und Clip) auf einem Stack. canvas.restore() stellt den zuletzt gespeicherten Zustand wieder her. Dies ist für temporäre Transformationen notwendig: Zustand speichern, translate/rotate anwenden, zeichnen, dann wiederherstellen. save und restore sind leichtgewichtig und beeinträchtigen die Leistung bei angemessener Nutzung (weniger als 10–15 Verschachtelungsebenen) nicht.

invalidate und postInvalidate

invalidate() ist eine View-Methode, die dem System mitteilt, dass der Inhalt der View veraltet ist und neu gezeichnet werden muss. Der Aufruf von invalidate initiiert einen neuen draw-Zyklus, in dem onDraw aufgerufen wird. invalidate darf nur vom UI-Thread (Hauptthread) aus aufgerufen werden. Für den Aufruf aus einem Hintergrundthread wird postInvalidate verwendet.

postInvalidate() ist eine threadsichere Version von invalidate, die eine Neuzeichnungsanforderung über Handler an die Warteschlange des Hauptthreads sendet. Sie wird in Hintergrundaufgaben verwendet, wenn die View nach Abschluss des Datenladens oder von Berechnungen aktualisiert werden muss. Sie kann mit runOnUiThread zur UI-Synchronisation kombiniert werden.

Für teilweises Neuzeichnen verwenden Sie invalidate(Rect dirty) oder invalidate(int l, int t, int r, int b). Dies teilt dem System mit, dass sich nur der angegebene Bereich geändert hat, nicht die gesamte View. Android optimiert das Zeichnen, indem es nur das dirty rect neu zeichnet, was die Leistung bei Animationen mit teilweisen Aktualisierungen erheblich verbessert.

Kotlin-Codebeispiele

Schauen wir uns praktische Beispiele zum Überschreiben von onDraw zum Erstellen benutzerdefinierter Views in Android mit Kotlin an.

Benutzerdefinierte View — Kreisförmiger Fortschritt

Dieses Beispiel erstellt einen kreisförmigen Fortschrittsindikator mit animierter Füllung. onDraw zeichnet zwei Kreise: einen grauen Hintergrundkreis und einen farbigen Füllkreis, dessen Bogen durch den aktuellen Fortschritt bestimmt wird. Der Aufruf von invalidate in setProgress stellt die Neuzeichnung sicher, wenn sich der Wert ändert.

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

Benutzerdefinierte View — Verlaufs-Hintergrund mit Text

Dieses Beispiel zeichnet ein Rechteck mit einem Verlauf und Text darüber. Der Verlauf wird über LinearGradient (Shader) erstellt, der Text über drawText. Beide Paint-Objekte werden einmal im Konstruktor erstellt, während onDraw nur die Rechteckgröße basierend auf der aktuellen View-Breite aktualisiert.

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("Hello from Canvas",
                      xCenter, yCenter - yOffset,
                      textPaint)
    }
}

Animierte Uhr mit invalidate

Dieses Beispiel erstellt eine animierte Uhr, die die Zeichnung alle 1000 Millisekunden aktualisiert. postDelayed innerhalb von onDraw ruft nach einer Sekunde invalidate auf und erzeugt so eine endlose Neuzeichnungsschleife. Die Uhrzeiger werden über drawLine mit unterschiedlichen Längen und Dicken gezeichnet.

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

Häufig gestellte Fragen

Kann onDraw direkt aufgerufen werden?

Nein, onDraw sollte nicht direkt aufgerufen werden. Verwenden Sie zum Anfordern einer Neuzeichnung invalidate() (vom UI-Thread) oder postInvalidate() (von einem Hintergrundthread). Das System entscheidet, wann onDraw aufgerufen wird, und optimiert das Zeichnen durch Zusammenfassen mehrerer invalidate-Aufrufe in einem Durchgang.

Warum wird onDraw nach invalidate nicht aufgerufen?

Gründe: Die View ist ausgeblendet (setVisibility(GONE) oder INVISIBLE); die View wurde nicht zur Window-Hierarchie hinzugefügt; die View-Größe ist 0 (Breite oder Höhe = 0); setWillNotDraw(true) wird aufgerufen (standardmäßig true für ViewGroup). Überprüfen Sie beim Debuggen jeden dieser Punkte.

Wie oft kann onDraw aufgerufen werden?

Bei 60 fps kann onDraw bis zu 60 Mal pro Sekunde aufgerufen werden. Bei 120 fps (auf Geräten mit 120 Hz Displays) — bis zu 120 Mal. Jeder Aufruf sollte innerhalb von etwa 8–16 Millisekunden abgeschlossen sein. Während aktiver Animationen über ObjectAnimator oder ValueAnimator wird die Häufigkeit durch die Anzahl der Animationsframes bestimmt.

Was ist der Unterschied zwischen onDraw und dispatchDraw?

onDraw ist für das Zeichnen des eigenen Inhalts der View verantwortlich. dispatchDraw ist für das Zeichnen der untergeordneten Views (in ViewGroup) verantwortlich. dispatchDraw wird nach onDraw aufgerufen und durchläuft rekursiv alle untergeordneten Elemente. Für eine normale View (keine ViewGroup) ist dispatchDraw leer.

Kann Canvas außerhalb von onDraw verwendet werden?

Ja, Canvas kann für eine Bitmap über Canvas(bitmap) erstellt und in jedem Thread gezeichnet werden. Dies wird verwendet, um komplexe Grafiken im Hintergrund vorzubereiten. Der an onDraw übergebene Canvas gehört jedoch dem System und darf nur im UI-Thread innerhalb der onDraw-Methode verwendet werden.

Zusammenfassung

  • onDraw(Canvas) — eine wichtige View-Methode für benutzerdefiniertes Zeichnen mit der Canvas API in Android
  • Zeichenzyklus besteht aus den Phasen measure, layout und draw — onDraw wird in der draw-Phase aufgerufen
  • Canvas API enthält die Methoden drawCircle, drawRect, drawPath, drawBitmap, drawText und weitere
  • invalidate() fordert Neuzeichnung vom UI-Thread an, postInvalidate() von einem Hintergrundthread
  • Teilweises Neuzeichnen über invalidate(Rect) optimiert das Rendern durch Aktualisierung nur des Dirty-Bereichs
  • onDraw-Leistung ist entscheidend: Objekterstellung innerhalb der Methode verursacht GC und Frame-Drops
  • Hardwarebeschleunigung (seit API 11) beschleunigt Canvas-Operationen automatisch über die GPU

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch