dispatchDraw(): Was es ist, Aufrufmechanismus und Unterschied zu onDraw

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

dispatchDraw() ist eine Methode der ViewGroup-Klasse, die für das rekursive Zeichnen aller Child-Views in der Android-Hierarchie verantwortlich ist. Laut Android Developers Documentation (2026) wird dispatchDraw automatisch nach onDraw in der draw()-Methode der Haupt-View aufgerufen und durchläuft alle Kindelemente, um deren eigenes draw() aufzurufen. Entwickler überschreiben dispatchDraw in benutzerdefinierten ViewGroups, um Effekte hinzuzufügen, Grafiken über Kinder zu legen oder die Zeichenreihenfolge zu ändern.

Wichtigste Punkte

  • dispatchDraw(Canvas canvas) ist eine protected-Methode von ViewGroup, die nach onDraw zum Zeichnen der Child-Views aufgerufen wird
  • draw(Canvas canvas) ist eine public-final-Methode von View, die nacheinander onDraw, dispatchDraw und onDrawForeground aufruft
  • onDraw zeichnet den Inhalt der View selbst, während dispatchDraw alle Kindelemente zeichnet
  • setWillNotDraw(true) ist eine Optimierung für ViewGroups, die keinen eigenen Inhalt zeichnen, sondern nur Kindelemente
  • Das Überschreiben von dispatchDraw wird verwendet, um Effekte (Blur, Overlay) anzuwenden oder das Zeichnen von Kindern zu animieren

Was ist dispatchDraw()?

dispatchDraw(Canvas canvas) ist eine protected-Methode der ViewGroup-Klasse, die das Android-System aufruft, um alle Child-Views des aktuellen Containers zu zeichnen. dispatchDraw ist Teil der Standard-Zeichen-Pipeline: Zunächst wird onDraw ausgeführt (Zeichnen des View-eigenen Inhalts), dann dispatchDraw (rekursives Zeichnen der Kinder), dann onDrawForeground (Zeichnen des Vordergrunds und der Scrollleisten). Die Methode ist nicht für den direkten Aufruf aus Anwendungscode vorgesehen.

Die Standardimplementierung von dispatchDraw in ViewGroup durchläuft alle Child-Views, überprüft ihre Sichtbarkeit und ruft draw(Canvas) für jede auf. Die Durchlaufreihenfolge entspricht den Kinderindizes (von 0 bis childCount - 1). Wenn sich Child-Views überlappen, werden die späteren in der Liste über den früheren gezeichnet. Durch Ändern der Reihenfolge in dispatchDraw kann der Z-Order des Zeichnens verändert werden.

Für eine View (keine ViewGroup) ist die dispatchDraw-Methode leer — eine normale View hat keine Kindelemente, also gibt es nichts zu zeichnen. Die Methode existiert in der Basisklasse View, wird aber nur auf ViewGroup-Instanzen aufgerufen. Ein Entwickler kann über das Standardverhalten von dispatchDraw prüfen, ob eine View Kindelemente hat, aber oft ist die Prüfung instanceof ViewGroup einfacher.

Zeichen-Pipeline: onDraw, dispatchDraw, onDrawForeground

Die draw(Canvas)-Methode der View-Klasse organisiert eine dreistufige Zeichen-Pipeline. Die erste Stufe ist der Aufruf von onDraw(canvas), bei dem die View ihren eigenen Inhalt zeichnet. Die zweite Stufe ist der Aufruf von dispatchDraw(canvas), der das Zeichnen der Child-Views auslöst. Die dritte Stufe ist onDrawForeground(canvas), zuständig für die Vordergrundschicht, Bildlaufleisten und Ripple-Effekte. Diese Reihenfolge gewährleistet die korrekte Überlagerungsreihenfolge der grafischen Schichten.

onDraw wird immer vor dispatchDraw ausgeführt. Das bedeutet, dass der Inhalt der Eltern-View unter den Child-Views angezeigt wird. Wenn etwas über den Kindern gezeichnet werden muss, geschieht dies in onDrawForeground oder in einer überschriebenen dispatchDraw-Methode durch Aufruf von super.dispatchDraw(canvas) und anschließendem Darüberzeichnen. Der Hintergrund wird noch vor onDraw gezeichnet — in drawBackground(canvas) innerhalb der draw()-Methode.

Bei Hardwarebeschleunigung arbeitet die Zeichen-Pipeline über die GPU. Die View wird in eine DisplayList gezeichnet — eine Liste von Zeichenbefehlen, die zwischengespeichert und wiederverwendet wird. dispatchDraw fügt im hardwarebeschleunigten Modus die DisplayLists der Child-Views zur gesamten DisplayList der Szene hinzu. Das Ändern von dispatchDraw kann zur Ungültigmachung der DisplayList und zum Neuaufbau des Caches führen, was die Leistung beeinträchtigt.

MethodeAufrufreihenfolgeZweck
drawBackground1Zeichnen des Hintergrunds (background drawable)
onDraw2Zeichnen des View-eigenen Inhalts
dispatchDraw3Zeichnen aller Child-Views (nur ViewGroup)
onDrawForeground4Zeichnen von Vordergrund, Bildlaufleiste und Ripple-Effekt

Unterschied zwischen dispatchDraw und onDraw

onDraw ist für das Zeichnen des View-eigenen Inhalts verantwortlich — Formen, Text, Bilder, die zu diesem spezifischen Element gehören. dispatchDraw ist für das Zeichnen der Child-Views verantwortlich — aller Elemente, die sich innerhalb der ViewGroup befinden. Wenn eine ViewGroup dispatchDraw nicht überschreibt, wird die Implementierung aus ViewGroup verwendet, die einfach rekursiv childCount durchläuft und draw für jedes Kind aufruft.

Für eine ViewGroup, die keinen eigenen Inhalt zeichnet (z. B. FrameLayout, LinearLayout), kann onDraw durch Setzen von setWillNotDraw(true) optimiert werden. In diesem Fall wird onDraw nie aufgerufen, was Ressourcen spart. dispatchDraw funktioniert weiterhin und ruft draw für die Kindelemente auf. Alle Standard-ViewGroups (LinearLayout, RelativeLayout, ConstraintLayout) verwenden setWillNotDraw(true).

Wenn Sie dispatchDraw ohne Aufruf von super.dispatchDraw(canvas) überschreiben, werden die Child-Views nicht gezeichnet. Dies kann zum vorübergehenden Ausblenden aller Kinder nützlich sein, verursacht aber in den meisten Fällen Fehler. Empfohlene Vorgehensweise: Rufen Sie super.dispatchDraw(canvas) am Anfang der überschriebenen Methode auf und fügen Sie dann Ihre eigene Grafik (z. B. ein Overlay mit Alphakanal) über den Kindern hinzu.

Beispiel zum Überschreiben von dispatchDraw in Kotlin

Erstellen wir eine OverlayViewGroup — eine benutzerdefinierte ViewGroup, die über allen Child-Views eine halbtransparente Schicht mit einer Textmarkierung hinzufügt. dispatchDraw ruft zunächst super auf (zeichnet alle Kinder), zeichnet dann das Overlay-Rechteck und den Text. Paint wird im Konstruktor erstellt, um Allokationen in der draw-Schleife zu vermeiden.

kotlin
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("VORSCHAU-MODUS",
            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))
    }
}

Animierter Z-Order durch dispatchDraw

Das folgende Beispiel demonstriert das Ändern der Reihenfolge des Zeichnens von Kindelementen. CircularRevealLayout überschreibt dispatchDraw und zeichnet die Kinder in umgekehrter Reihenfolge, wodurch ein umgekehrter Z-Order-Effekt entsteht. Für die Animation wird basierend auf dem animierten Offset-Wert eine zyklische Verschiebung des Zeichenindex hinzugefügt.

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

Wann dispatchDraw in Android verwendet wird

dispatchDraw wird in Szenarien verwendet, in denen Sie den Zeichenprozess der Child-Views beeinflussen müssen, ohne den eigenen Inhalt der ViewGroup zu beeinträchtigen. Hauptszenarien: Anwenden eines gemeinsamen Effekts (Overlay, Schatten, Verlauf) über allen Kindern; Ändern des Z-Order zum Erzeugen von Tiefeneffekten; Animieren des Erscheinens oder Verschwindens von Kindelementen durch Canvas-Transformationen.

Wenn Sie Grafiken unterhalb der Kindelemente anwenden müssen (Hintergrundeffekt), verwenden Sie onDraw — dispatchDraw wird danach aufgerufen. Wenn Grafiken über den Kindern liegen sollen — verwenden Sie dispatchDraw mit vorherigem super-Aufruf, dann Canvas.draw. Wenn Sie eine globale Farb- oder Transparenzänderung benötigen, verwenden Sie canvas.saveLayerAlpha() in dispatchDraw, um das Zeichnen der Kinder zu umschließen.

Nicht empfohlen wird dispatchDraw für: 1) Zeichnen komplexer Animationen in Echtzeit (verwenden Sie invalidate und onDraw); 2) Erstellen von Screenshots einer ViewGroup (verwenden Sie buildDrawingCache() oder View.draw(Canvas)); 3) Ändern von Child-Views (Koordinaten, Größen — das sind Aufgaben von onLayout, nicht von dispatchDraw). dispatchDraw dient nur zum Anwenden visueller Effekte.

Häufig gestellte Fragen

Kann dispatchDraw direkt ohne das System aufgerufen werden?

Nein, dispatchDraw ist eine protected-Methode, die vom Android-System innerhalb der öffentlichen draw()-Methode aufgerufen wird. Ein direkter Aufruf von dispatchDraw ist sinnlos, da er keine vorbereitenden Aktionen (Speichern des Canvas, Zeichnen von Hintergrund und Vordergrund) ausführt. Verwenden Sie stattdessen View.draw(Canvas) zum programmatischen Zeichnen auf einen beliebigen Canvas.

Was passiert, wenn super.dispatchDraw nach benutzerdefiniertem Zeichnen aufgerufen wird?

Wenn Sie super.dispatchDraw(canvas) nach Ihren eigenen Zeichenoperationen aufrufen, werden die Child-Views über der benutzerdefinierten Grafik gezeichnet. Dies ändert die Schichtreihenfolge: Zuerst wird die benutzerdefinierte Schicht gezeichnet, dann die Kinder. Wenn Sie die umgekehrte Situation benötigen (Grafik über den Kindern), rufen Sie zuerst super.dispatchDraw auf, dann Ihre eigenen Operationen.

Wie beeinflusst dispatchDraw die Leistung?

dispatchDraw ruft draw() für jede Child-View auf, die Gesamtzeit ist proportional zur Anzahl der Kinder. Bei Hardwarebeschleunigung kann das Hinzufügen von Canvas-Operationen in dispatchDraw die DisplayList ungültig machen und einen Cache-Neuaufbau verursachen. Für 5–10 Kinder ist die Auswirkung minimal, für 50+ Kinder wird empfohlen, komplexe Überlagerungen zwischenzuspeichern.

Warum wird dispatchDraw für eine View nicht aufgerufen?

Eine View (keine ViewGroup) hat keine Kindelemente, daher führt dispatchDraw keine nützliche Arbeit aus. Die Methode existiert jedoch in der Basisklasse View aus Polymorphiegründen: Der Code in draw() ruft dispatchDraw für jede View auf, aber die View-Implementierung enthält keine Logik zum Zeichnen von Kindern. Nur ViewGroup überschreibt dispatchDraw.

Kann der Canvas in dispatchDraw verändert werden?

Ja, dispatchDraw akzeptiert einen Canvas, der vor dem Aufruf von super.dispatchDraw transformiert werden kann (translate, rotate, scale). Dies wird verwendet, um die gesamte Kindermenge als Einheit zu animieren. Nach Abschluss von super.dispatchDraw wird empfohlen, den Canvas in seinen ursprünglichen Zustand zurückzuversetzen.

Zusammenfassung

  • dispatchDraw(Canvas) ist eine ViewGroup-Methode zum rekursiven Zeichnen aller Child-Views nach onDraw
  • Zeichen-Pipeline: drawBackground → onDraw → dispatchDraw → onDrawForeground
  • onDraw zeichnet den Inhalt der View selbst, dispatchDraw zeichnet den Inhalt der Kindelemente
  • setWillNotDraw(true) optimiert ViewGroup durch Überspringen von onDraw, aber dispatchDraw funktioniert weiter
  • Das Überschreiben von dispatchDraw wird zum Anwenden von Effekten, Ändern des Z-Order und Canvas-Transformationen von Kindern verwendet
  • Die Reihenfolge von super.dispatchDraw und benutzerdefiniertem Zeichnen bestimmt, was über den Kindern erscheint
  • Für eine normale View (keine ViewGroup) ist dispatchDraw leer — sie hat keine Kindelemente

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