dispatchDraw(): o que é, mecanismo de chamada e diferença do onDraw

Autor: IT Sectr Publicado: 2026-07-22 Tempo de leitura: 9 min

dispatchDraw() é um método da classe ViewGroup responsável pelo desenho recursivo de todas as Views filhas na hierarquia do Android. De acordo com a Documentação para Desenvolvedores Android (2026), dispatchDraw é chamado automaticamente após onDraw no método draw() da View principal e percorre todos os elementos filhos, chamando seu próprio draw(). Desenvolvedores sobrescrevem dispatchDraw em ViewGroups personalizados para adicionar efeitos, sobrepor gráficos sobre os filhos ou alterar a ordem de desenho.

Pontos principais

  • dispatchDraw(Canvas canvas) é um método protected do ViewGroup chamado após onDraw para desenhar as Views filhas
  • draw(Canvas canvas) é um método public final de View que chama sequencialmente onDraw, dispatchDraw e onDrawForeground
  • onDraw desenha o conteúdo da própria View, enquanto dispatchDraw desenha todos os elementos filhos
  • setWillNotDraw(true) é uma otimização para ViewGroup que não desenha seu próprio conteúdo, apenas elementos filhos
  • Sobrescrever dispatchDraw é usado para aplicar efeitos (blur, overlay) ou animar o desenho de elementos filhos

O que é dispatchDraw()?

dispatchDraw(Canvas canvas) é um método protected da classe ViewGroup que o sistema Android chama para desenhar todas as Views filhas do contêiner atual. O dispatchDraw faz parte do pipeline padrão de draw: primeiro o onDraw é executado (desenho do conteúdo da própria View), depois o dispatchDraw (desenho recursivo dos filhos), depois o onDrawForeground (desenho do foreground e scrollbars). O método não foi projetado para ser chamado diretamente do código da aplicação.

A implementação padrão do dispatchDraw no ViewGroup percorre todas as Views filhas, verifica sua visibilidade e chama draw(Canvas) para cada uma. A ordem de travessia corresponde aos índices dos filhos (de 0 a childCount - 1). Se as Views filhas se sobrepõem, as últimas na lista são desenhadas sobre as primeiras. Alterar a ordem no dispatchDraw permite modificar o Z-order do desenho.

Para uma View (não ViewGroup), o método dispatchDraw está vazio — uma View normal não tem elementos filhos, então não há nada para desenhar. O método existe na classe base View, mas só é chamado em instâncias de ViewGroup. Um desenvolvedor pode verificar se uma View tem elementos filhos através do comportamento padrão do dispatchDraw, mas geralmente é mais simples verificar instanceof ViewGroup.

Pipeline de desenho: onDraw, dispatchDraw, onDrawForeground

O método draw(Canvas) da classe View organiza um pipeline de desenho de três estágios. O primeiro estágio é chamar onDraw(canvas), onde a View desenha seu próprio conteúdo. O segundo estágio é chamar dispatchDraw(canvas), que aciona o desenho das Views filhas. O terceiro estágio é onDrawForeground(canvas), responsável pela camada de foreground, scrollbars e efeitos ripple. Essa sequência garante a ordem correta de sobreposição das camadas gráficas.

onDraw sempre é executado antes do dispatchDraw. Isso significa que o conteúdo da View pai é exibido abaixo das Views filhas. Se você precisar desenhar algo sobre os filhos, isso é feito no onDrawForeground ou em um dispatchDraw sobrescrito chamando super.dispatchDraw(canvas) e depois desenhando por cima. O fundo é desenhado antes mesmo do onDraw — em drawBackground(canvas) dentro do método draw().

Com a aceleração de hardware, o pipeline de draw funciona através da GPU. A View é desenhada em um DisplayList — uma lista de comandos de desenho que é armazenada em cache e reutilizada. O dispatchDraw em modo acelerado por hardware adiciona os DisplayLists das Views filhas ao DisplayList geral da cena. Modificar o dispatchDraw pode invalidar o DisplayList e causar a reconstrução do cache, o que impacta o desempenho.

MétodoOrdem de chamadaPropósito
drawBackground1Desenho do fundo (background drawable)
onDraw2Desenho do conteúdo da própria View
dispatchDraw3Desenho de todas as Views filhas (apenas ViewGroup)
onDrawForeground4Desenho de foreground, scrollbar e efeito ripple

Diferença entre dispatchDraw e onDraw

onDraw é responsável por desenhar o conteúdo da própria View — formas, texto, imagens que pertencem a este elemento específico. dispatchDraw é responsável por desenhar as Views filhas — todos os elementos contidos dentro do ViewGroup. Se um ViewGroup não sobrescreve dispatchDraw, a implementação do ViewGroup é usada, que simplesmente percorre recursivamente childCount e chama draw para cada filho.

Para um ViewGroup que não desenha seu próprio conteúdo (por exemplo, FrameLayout, LinearLayout), onDraw pode ser otimizado definindo setWillNotDraw(true). Nesse caso, onDraw nunca é chamado, economizando recursos. dispatchDraw continua funcionando e chama draw para os elementos filhos. Todos os ViewGroups padrão (LinearLayout, RelativeLayout, ConstraintLayout) usam setWillNotDraw(true).

Se você sobrescrever dispatchDraw sem chamar super.dispatchDraw(canvas), as Views filhas não serão desenhadas. Isso pode ser útil para ocultar temporariamente todos os filhos, mas na maioria dos casos causa erros. Prática recomendada: chamar super.dispatchDraw(canvas) no início do método sobrescrito e, em seguida, adicionar seus próprios gráficos (por exemplo, uma sobreposição com canal alfa) sobre os filhos.

Exemplo de sobrescrita de dispatchDraw em Kotlin

Vamos criar um OverlayViewGroup — um ViewGroup personalizado que adiciona uma camada semitransparente com um rótulo de texto sobre todas as Views filhas. dispatchDraw primeiro chama super (desenhando todos os filhos), depois desenha o retângulo de sobreposição e o texto. Paint é criado no construtor para evitar alocações no loop de draw.

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("MODO DE VISUALIZAÇÃO PRÉVIA",
            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 animado via dispatchDraw

O exemplo a seguir demonstra alteração da ordem de desenho dos elementos filhos. CircularRevealLayout sobrescreve dispatchDraw e desenha os filhos em ordem inversa, criando um efeito de Z-order invertido. Para animação, um deslocamento cíclico do índice de desenho é adicionado com base no valor animado 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))
    }
}

Quando usar dispatchDraw no Android

dispatchDraw é usado em cenários onde você precisa influenciar o processo de desenho das Views filhas sem afetar o conteúdo próprio do ViewGroup. Principais cenários: aplicar um efeito comum (overlay, shadow, gradient) sobre todos os filhos; alterar o Z-order para criar efeitos de profundidade; animar o aparecimento ou desaparecimento de elementos filhos através de transformações de Canvas.

Se você precisar aplicar gráficos abaixo dos elementos filhos (efeito de fundo), use onDraw — dispatchDraw é chamado depois. Se os gráficos devem ficar sobre os filhos — use dispatchDraw chamando super primeiro, depois Canvas.draw. Se você precisar de uma alteração global de cor ou transparência, é conveniente usar canvas.saveLayerAlpha() no dispatchDraw, envolvendo o desenho dos filhos.

Não é recomendado usar dispatchDraw para: 1) desenhar animações complexas em tempo real (use invalidate e onDraw); 2) criar capturas de tela de um ViewGroup (use buildDrawingCache() ou View.draw(Canvas)); 3) modificar Views filhas (coordenadas, tamanhos — são tarefas de onLayout, não de dispatchDraw). dispatchDraw é apenas para aplicar efeitos visuais.

Perguntas frequentes

É possível chamar dispatchDraw diretamente sem o sistema?

Não, dispatchDraw é um método protected chamado pelo sistema Android dentro do método público draw(). Uma chamada direta ao dispatchDraw não faz sentido porque ele não executa ações preparatórias (salvar Canvas, desenhar fundo e foreground). Em vez disso, use View.draw(Canvas) para desenho programático em um Canvas arbitrário.

O que acontece quando super.dispatchDraw é chamado após o desenho personalizado?

Se você chamar super.dispatchDraw(canvas) após suas próprias operações de desenho, as Views filhas serão desenhadas sobre os gráficos personalizados. Isso altera a ordem das camadas: primeiro a camada personalizada é desenhada, depois os filhos. Se você precisar da situação oposta (gráficos sobre os filhos), chame super.dispatchDraw primeiro, depois suas próprias operações.

Como o dispatchDraw afeta o desempenho?

dispatchDraw chama draw() para cada View filha, e o tempo total é proporcional ao número de filhos. Com aceleração de hardware, adicionar operações de Canvas no dispatchDraw pode invalidar o DisplayList e causar reconstrução do cache. Para 5–10 filhos o impacto é mínimo, para 50+ filhos é recomendado armazenar em cache sobreposições complexas.

Por que dispatchDraw não é chamado para uma View?

Uma View (não ViewGroup) não tem elementos filhos, então dispatchDraw não realiza trabalho útil. No entanto, o método existe na classe base View para polimorfismo: o código em draw() chama dispatchDraw para qualquer View, mas a implementação de View não contém lógica de desenho de filhos. Apenas ViewGroup sobrescreve dispatchDraw.

É possível modificar o Canvas no dispatchDraw?

Sim, dispatchDraw aceita um Canvas e ele pode ser transformado antes de chamar super.dispatchDraw (translate, rotate, scale). Isso é usado para animar todo o conjunto de filhos como uma única unidade. Após a conclusão do super.dispatchDraw, é recomendado restaurar o Canvas ao seu estado original.

Resumo

  • dispatchDraw(Canvas) é um método do ViewGroup para desenho recursivo de todas as Views filhas após onDraw
  • Pipeline de draw: drawBackground → onDraw → dispatchDraw → onDrawForeground
  • onDraw desenha o conteúdo da própria View, dispatchDraw desenha o conteúdo dos elementos filhos
  • setWillNotDraw(true) otimiza ViewGroup pulando onDraw, mas dispatchDraw continua funcionando
  • Sobrescrever dispatchDraw é usado para aplicar efeitos, alterar Z-order e transformações de Canvas nos filhos
  • A ordem de super.dispatchDraw e do desenho personalizado determina o que aparece sobre os filhos
  • Para uma View normal (não ViewGroup) dispatchDraw está vazio — não tem elementos filhos

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também