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 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.
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étodo | Ordem de chamada | Propósito |
|---|---|---|
| drawBackground | 1 | Desenho do fundo (background drawable) |
| onDraw | 2 | Desenho do conteúdo da própria View |
| dispatchDraw | 3 | Desenho de todas as Views filhas (apenas ViewGroup) |
| onDrawForeground | 4 | Desenho de foreground, scrollbar e efeito ripple |
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.
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.
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))
}
}
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.
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))
}
}
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
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.
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.
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.
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.
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
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.
Leia também