dispatchDraw() : ce que c'est, mécanisme d'appel et différence avec onDraw

Auteur : IT Sectr Publié le : 2026-07-22 Temps de lecture : 9 min

dispatchDraw() est une méthode de la classe ViewGroup responsable du dessin récursif de toutes les vues filles dans la hiérarchie Android. Selon la documentation développeurs Android (2026), dispatchDraw est appelé automatiquement après onDraw dans la méthode draw() de la vue principale et parcourt tous les éléments enfants, appelant leur propre draw(). Les développeurs redéfinissent dispatchDraw dans des ViewGroups personnalisés pour ajouter des effets, superposer des graphiques sur les enfants ou modifier l'ordre de dessin.

Points clés

  • dispatchDraw(Canvas canvas) est une méthode protected de ViewGroup appelée après onDraw pour dessiner les vues filles
  • draw(Canvas canvas) est une méthode public final de View qui appelle séquentiellement onDraw, dispatchDraw et onDrawForeground
  • onDraw dessine le contenu de la vue elle-même, tandis que dispatchDraw dessine tous les éléments enfants
  • setWillNotDraw(true) est une optimisation pour ViewGroup qui ne dessine pas son propre contenu, seulement les éléments enfants
  • La redéfinition de dispatchDraw est utilisée pour appliquer des effets (flou, superposition) ou animer le dessin des éléments enfants

Qu'est-ce que dispatchDraw() ?

dispatchDraw(Canvas canvas) est une méthode protected de la classe ViewGroup que le système Android appelle pour dessiner toutes les vues filles du conteneur actuel. dispatchDraw fait partie du pipeline de dessin standard : d'abord onDraw s'exécute (dessin du contenu de la vue elle-même), puis dispatchDraw (dessin récursif des enfants), puis onDrawForeground (dessin du premier plan et des barres de défilement). La méthode n'est pas destinée à être appelée directement depuis le code de l'application.

L'implémentation standard de dispatchDraw dans ViewGroup parcourt toutes les vues filles, vérifie leur visibilité et appelle draw(Canvas) pour chacune. L'ordre de parcours correspond aux indices des enfants (de 0 à childCount - 1). Si les vues filles se chevauchent, les dernières de la liste sont dessinées par-dessus les premières. Modifier l'ordre dans dispatchDraw permet de changer le Z-order du dessin.

Pour une View (pas ViewGroup), la méthode dispatchDraw est vide — une vue normale n'a pas d'éléments enfants, donc rien à dessiner. La méthode existe dans la classe de base View mais n'est appelée que sur les instances de ViewGroup. Un développeur peut vérifier si une vue a des éléments enfants via le comportement par défaut de dispatchDraw, mais il est souvent plus simple de vérifier instanceof ViewGroup.

Pipeline de dessin : onDraw, dispatchDraw, onDrawForeground

La méthode draw(Canvas) de la classe View organise un pipeline de dessin en trois étapes. La première étape est l'appel de onDraw(canvas), où la vue dessine son propre contenu. La deuxième étape est l'appel de dispatchDraw(canvas), qui déclenche le dessin des vues filles. La troisième étape est onDrawForeground(canvas), responsable de la couche de premier plan, des barres de défilement et des effets d'ondulation. Cette séquence garantit l'ordre correct de superposition des couches graphiques.

onDraw est toujours exécuté avant dispatchDraw. Cela signifie que le contenu de la vue parent est affiché sous les vues filles. Si vous devez dessiner quelque chose par-dessus les enfants, cela se fait dans onDrawForeground ou dans un dispatchDraw redéfini en appelant super.dispatchDraw(canvas) puis en dessinant par-dessus. L'arrière-plan est dessiné avant même onDraw — dans drawBackground(canvas) à l'intérieur de la méthode draw().

Avec l'accélération matérielle, le pipeline de dessin fonctionne via le GPU. La vue est dessinée dans un DisplayList — une liste de commandes de dessin qui est mise en cache et réutilisée. dispatchDraw en mode accéléré matériel ajoute les DisplayLists des vues filles au DisplayList global de la scène. La modification de dispatchDraw peut invalider le DisplayList et provoquer une reconstruction du cache, ce qui impacte les performances.

MéthodeOrdre d'appelObjectif
drawBackground1Dessin de l'arrière-plan (background drawable)
onDraw2Dessin du contenu de la vue elle-même
dispatchDraw3Dessin de toutes les vues filles (ViewGroup uniquement)
onDrawForeground4Dessin du premier plan, barre de défilement et effet d'ondulation

Différence entre dispatchDraw et onDraw

onDraw est responsable du dessin du contenu de la vue elle-même — formes, texte, images qui appartiennent à cet élément spécifique. dispatchDraw est responsable du dessin des vues filles — tous les éléments contenus dans le ViewGroup. Si un ViewGroup ne redéfinit pas dispatchDraw, l'implémentation de ViewGroup est utilisée, qui parcourt simplement récursivement childCount et appelle draw pour chaque enfant.

Pour un ViewGroup qui ne dessine pas son propre contenu (par exemple, FrameLayout, LinearLayout), onDraw peut être optimisé en définissant setWillNotDraw(true). Dans ce cas, onDraw n'est jamais appelé, ce qui économise des ressources. dispatchDraw continue de fonctionner et appelle draw pour les éléments enfants. Tous les ViewGroups standard (LinearLayout, RelativeLayout, ConstraintLayout) utilisent setWillNotDraw(true).

Si vous redéfinissez dispatchDraw sans appeler super.dispatchDraw(canvas), les vues filles ne seront pas dessinées. Cela peut être utile pour masquer temporairement tous les enfants, mais dans la plupart des cas, cela provoque des erreurs. Pratique recommandée : appelez super.dispatchDraw(canvas) au début de la méthode redéfinie, puis ajoutez vos propres graphiques (par exemple, une superposition avec canal alpha) par-dessus les enfants.

Exemple de redéfinition de dispatchDraw en Kotlin

Créons un OverlayViewGroup — un ViewGroup personnalisé qui ajoute une couche semi-transparente avec un libellé de texte par-dessus toutes les vues filles. dispatchDraw appelle d'abord super (dessin de tous les enfants), puis dessine le rectangle de superposition et le texte. Paint est créé dans le constructeur pour éviter les allocations dans la boucle de dessin.

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("MODE AVANT-PREMIÈRE",
            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))
    }
}

Z-order animé via dispatchDraw

L'exemple suivant démontre le changement d'ordre du dessin des éléments enfants. CircularRevealLayout redéfinit dispatchDraw et dessine les enfants dans l'ordre inverse, créant un effet de Z-order inversé. Pour l'animation, un décalage cyclique de l'index de dessin est ajouté basé sur la valeur animée offset.

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

Quand utiliser dispatchDraw dans Android

dispatchDraw est utilisé dans les scénarios où vous devez influencer le processus de dessin des vues filles sans affecter le contenu propre du ViewGroup. Principaux scénarios : appliquer un effet commun (superposition, ombre, dégradé) par-dessus tous les enfants ; modifier le Z-order pour créer des effets de profondeur ; animer l'apparition ou la disparition d'éléments enfants via des transformations Canvas.

Si vous devez appliquer des graphiques en dessous des éléments enfants (effet d'arrière-plan), utilisez onDraw — dispatchDraw est appelé après. Si les graphiques doivent être au-dessus des enfants — utilisez dispatchDraw en appelant super d'abord, puis Canvas.draw. Si vous avez besoin d'un changement global de couleur ou de transparence, il est pratique d'utiliser canvas.saveLayerAlpha() dans dispatchDraw, en encapsulant le dessin des enfants.

Non recommandé d'utiliser dispatchDraw pour : 1) dessiner des animations complexes en temps réel (utilisez invalidate et onDraw) ; 2) créer des captures d'écran d'un ViewGroup (utilisez buildDrawingCache() ou View.draw(Canvas)) ; 3) modifier les vues filles (coordonnées, tailles — ce sont des tâches de onLayout, pas de dispatchDraw). dispatchDraw est uniquement pour appliquer des effets visuels.

Questions fréquentes

Peut-on appeler dispatchDraw directement sans le système ?

Non, dispatchDraw est une méthode protected appelée par le système Android à l'intérieur de la méthode publique draw(). Un appel direct à dispatchDraw n'a pas de sens car il n'effectue pas d'actions préparatoires (sauvegarde du Canvas, dessin de l'arrière-plan et du premier plan). Utilisez plutôt View.draw(Canvas) pour un dessin programmatique sur un Canvas arbitraire.

Que se passe-t-il lorsque super.dispatchDraw est appelé après un dessin personnalisé ?

Si vous appelez super.dispatchDraw(canvas) après vos propres opérations de dessin, les vues filles seront dessinées par-dessus les graphiques personnalisés. Cela change l'ordre des couches : d'abord la couche personnalisée est dessinée, puis les enfants. Si vous avez besoin de la situation inverse (graphiques par-dessus les enfants), appelez d'abord super.dispatchDraw, puis vos propres opérations.

Comment dispatchDraw affecte-t-il les performances ?

dispatchDraw appelle draw() pour chaque vue fille, et le temps total est proportionnel au nombre d'enfants. Avec l'accélération matérielle, ajouter des opérations Canvas dans dispatchDraw peut invalider le DisplayList et provoquer une reconstruction du cache. Pour 5 à 10 enfants, l'impact est minime, pour 50+ enfants, il est recommandé de mettre en cache les superpositions complexes.

Pourquoi dispatchDraw n'est-il pas appelé pour une View ?

Une View (pas ViewGroup) n'a pas d'éléments enfants, donc dispatchDraw n'effectue aucun travail utile. Cependant, la méthode existe dans la classe de base View pour le polymorphisme : le code dans draw() appelle dispatchDraw pour toute View, mais l'implémentation de View ne contient pas de logique de dessin d'enfants. Seul ViewGroup redéfinit dispatchDraw.

Peut-on modifier le Canvas dans dispatchDraw ?

Oui, dispatchDraw accepte un Canvas et il peut être transformé avant d'appeler super.dispatchDraw (translate, rotate, scale). Cela est utilisé pour animer l'ensemble des enfants comme une seule unité. Après la fin de super.dispatchDraw, il est recommandé de restaurer le Canvas à son état d'origine.

Résumé

  • dispatchDraw(Canvas) est une méthode de ViewGroup pour le dessin récursif de toutes les vues filles après onDraw
  • Pipeline de dessin : drawBackground → onDraw → dispatchDraw → onDrawForeground
  • onDraw dessine le contenu de la vue elle-même, dispatchDraw dessine le contenu des éléments enfants
  • setWillNotDraw(true) optimise ViewGroup en sautant onDraw, mais dispatchDraw continue de fonctionner
  • La redéfinition de dispatchDraw est utilisée pour appliquer des effets, modifier le Z-order et les transformations Canvas des enfants
  • L'ordre de super.dispatchDraw et du dessin personnalisé détermine ce qui apparaît par-dessus les enfants
  • Pour une View normale (pas ViewGroup), dispatchDraw est vide — elle n'a pas d'éléments enfants

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi