onDraw() — o que é, mecanismo de chamada e sobrescrita do método

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

onDraw() é um método chave da classe View no Android SDK responsável por desenhar o conteúdo de uma visualização. O sistema chama onDraw em cada atualização da aparência da View — durante a renderização inicial, após invalidate() ou quando as dimensões mudam. De acordo com a documentação do Android Developers (2026), sobrescrever onDraw usando a Canvas API é a principal forma de criar gráficos personalizados em aplicativos Android.

Principais pontos

  • onDraw(Canvas) — um método da View chamado pelo sistema para desenhar conteúdo no Canvas
  • invalidate() — uma solicitação para redesenhar a View, levando à chamada de onDraw no próximo ciclo de quadro
  • Canvas API fornece os métodos drawCircle, drawBitmap, drawText, drawPath e outros para desenho
  • O sistema Android realiza o desenho na thread de UI, portanto onDraw deve ser leve e rápido
  • Hardware acceleration acelera automaticamente o desenho através da GPU, a partir do Android 3.0 (API 11)

O que é onDraw()?

onDraw(Canvas canvas) é um método protected da classe android.view.View, que o sistema Android chama quando uma View precisa ser desenhada. O desenvolvedor sobrescreve este método para implementar desenho personalizado: formas, texto, imagens, gradientes, animações. O parâmetro Canvas é uma superfície gráfica na qual todas as operações de desenho são executadas.

A assinatura do método é simples: override fun onDraw(canvas: Canvas). Dentro deste método, não se deve criar novos objetos (para evitar a sobrecarga do GC), realizar operações longas ou trabalhar com a rede. View também inclui o método onDraw em seu ciclo de vida entre onLayout (cálculo de posições) e dispatchDraw (desenho de elementos filhos).

Ao herdar de View, sobrescrever onDraw é obrigatório para exibir qualquer conteúdo — caso contrário, a View ficará vazia. Ao herdar de subclasses existentes (TextView, ImageView, Button), sobrescrever onDraw é opcional e usado para adicionar gráficos extras sobre o conteúdo padrão.

Ciclo de renderização da View

Android realiza o desenho da View em uma sequência estritamente definida chamada a partir da thread principal (UI thread). O ciclo completo consiste em três fases: measure (medição de dimensões), layout (cálculo de posições) e draw (renderização). onDraw faz parte da fase draw e é chamado após as dimensões e a posição da View já terem sido determinadas.

Fase draw: dispatchDraw e onDraw

draw(Canvas canvas) é um método público de View que chama onDraw e dispatchDraw. O método draw não foi projetado para ser sobrescrito — em vez disso, onDraw é sobrescrito. Após a execução de onDraw para a View atual, dispatchDraw é chamado, que invoca recursivamente draw para todas as Views filhas (se a View atual for um contêiner ViewGroup).

Quando o sistema chama onDraw

onDraw é chamado nas seguintes condições: 1) a View se torna visível pela primeira vez (após setVisibility(VISIBLE)); 2) o aplicativo chama invalidate() nesta View ou em seu pai; 3) o tamanho da View muda (novo layout); 4) uma animação associada à View muda (via ValueAnimator ou ObjectAnimator); 5) o estado da View muda (pressed, focused, enabled).

Aceleração de hardware

Desde Android 3.0 (API 11), a maioria das operações do Canvas são aceleradas por hardware através da GPU. O desenvolvedor pode verificar se a aceleração está habilitada através de canvas.isHardwareAccelerated(). Com a aceleração de hardware, algumas operações do Canvas não são suportadas (por exemplo, clipPath com uma região não retangular) e podem ser ignoradas ou causar erros.

Canvas API para gráficos personalizados

Canvas fornece um rico conjunto de métodos de desenho. Todos os métodos funcionam no sistema de coordenadas atual, que pode ser modificado através de transformações (translate, rotate, scale, skew). Cada método aceita um objeto Paint que define cor, estilo, espessura de linha, efeitos e suavização.

Método do CanvasPropósitoParâmetros chave do Paint
drawCircleDesenhar um círculocenterX, centerY, radius, paint
drawRectDesenhar um retânguloleft, top, right, bottom, paint
drawLineDesenhar uma linhastartX, startY, endX, endY, paint
drawPathDesenhar um traçado arbitráriopath, paint
drawBitmapDesenhar uma imagem bitmapbitmap, srcRect, dstRect, paint
drawTextDesenhar textotext, x, y, paint
drawArcDesenhar um arco ou setorovalRect, startAngle, sweepAngle, useCenter, paint
drawOvalDesenhar uma ovalovalRect, paint

O objeto Paint

Paint define o estilo de desenho: cor (setColor), espessura de linha (setStrokeWidth), estilo de preenchimento (setStyle — FILL, STROKE, FILL_AND_STROKE), suavização (setAntiAlias), efeitos (setShadowLayer, setMaskFilter) e gradientes (setShader). Recomenda-se criar e configurar Paint uma vez no construtor da View, e não dentro de onDraw, para evitar a criação de objetos no loop de desenho.

Coordenadas e transformações

Canvas usa um sistema de coordenadas onde o eixo X aponta para a direita e o eixo Y para baixo. A origem (0, 0) é o canto superior esquerdo da View. Antes de chamar os métodos de desenho, o desenvolvedor pode alterar o sistema de coordenadas através de canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py). Todas as operações de desenho subsequentes serão realizadas no sistema transformado.

Desempenho do onDraw

onDraw é executado na thread principal de UI, e sua duração afeta diretamente a taxa de quadros (fps). Para manter 60 fps, o método onDraw deve ser concluído em até 16 milissegundos. Qualquer lentidão leva a quedas de quadros (jank), que visualmente aparece como gaguejo de animação ou atraso na rolagem.

Regras de desempenho do onDraw

Regras principais para otimização de onDraw incluem: 1) não criar objetos dentro de onDraw — todos os objetos Paint, Path, Rect devem ser campos de classe; 2) não alocar memória (new) — isso aciona coleta de lixo (GC) e quedas de quadros; 3) armazenar em cache operações complexas em um Bitmap via Bitmap.createBitmap e desenhar o Bitmap preparado; 4) não realizar operações de E/S ou carregamento de recursos.

Usando clipRect para otimização

clipRect limita a área de desenho a um retângulo especificado. É usado para evitar que o Canvas perca tempo desenhando pixels fora da área visível. É especialmente eficaz ao rolar listas grandes ou aplicar zoom: defina clipRect para a área visível (dirty rect), e o Canvas desenhará apenas o que é visível.

Layer — salvar e restaurar

canvas.save() salva o estado atual do Canvas (transformação e clip) em uma pilha. canvas.restore() restaura o último estado salvo. Isso é necessário para transformações temporárias: salve o estado, aplique translate/rotate, desenhe, depois restaure. save e restore são leves e não afetam o desempenho quando usados de forma razoável (menos de 10–15 níveis de aninhamento).

invalidate e postInvalidate

invalidate() é um método da View que informa ao sistema que o conteúdo da View está desatualizado e precisa ser redesenhado. Chamar invalidate inicia um novo ciclo de draw no qual onDraw será chamado. invalidate deve ser chamado apenas da thread de UI (main thread). Para chamar de uma thread em segundo plano, use postInvalidate.

postInvalidate() é uma versão thread-safe de invalidate que envia uma solicitação de redesenho para a fila da thread principal através de Handler. É usada em tarefas em segundo plano quando a View precisa ser atualizada após a conclusão do carregamento de dados ou cálculos. Pode ser combinada com runOnUiThread para sincronização com a UI.

Para redesenho parcial, use invalidate(Rect dirty) ou invalidate(int l, int t, int r, int b). Isso informa ao sistema que apenas a área especificada mudou, não a View inteira. O Android otimiza o desenho redesenhando apenas o dirty rect, melhorando significativamente o desempenho em animações com atualizações parciais.

Exemplos de código em Kotlin

Vamos ver exemplos práticos de sobrescrita de onDraw para criar Views personalizadas no Android usando Kotlin.

View personalizada — Progresso circular

Este exemplo cria um indicador de progresso circular com preenchimento animado. onDraw desenha dois círculos: um círculo de fundo cinza e um círculo colorido cujo arco é determinado pelo progresso atual. Chamar invalidate em setProgress garante o redesenho quando o valor muda.

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

View personalizada — Fundo gradiente com texto

Este exemplo desenha um retângulo com gradiente e texto sobre ele. O gradiente é criado via LinearGradient (Shader), e o texto via drawText. Ambos os objetos Paint são criados uma vez no construtor, enquanto onDraw apenas atualiza o tamanho do retângulo com base na largura atual da View.

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

Relógio animado usando invalidate

Este exemplo cria um relógio animado que atualiza o desenho a cada 1000 milissegundos. postDelayed dentro de onDraw chama invalidate após um segundo, criando um loop infinito de redesenho. Os ponteiros do relógio são desenhados via drawLine com diferentes comprimentos e espessuras.

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

Perguntas frequentes

Pode-se chamar onDraw diretamente?

Não, não se deve chamar onDraw diretamente. Para solicitar um redesenho, use invalidate() (da thread de UI) ou postInvalidate() (de uma thread em segundo plano). O sistema decidirá quando chamar onDraw e otimizará o desenho combinando múltiplas chamadas invalidate em uma única passagem.

Por que onDraw não é chamado após invalidate?

Razões: a View está oculta (setVisibility(GONE) ou INVISIBLE); a View não foi adicionada à hierarquia da Window; o tamanho da View é 0 (width ou height = 0); setWillNotDraw(true) é chamado (verdadeiro por padrão para ViewGroup). Verifique cada um desses pontos ao depurar.

Com que frequência onDraw pode ser chamado?

A 60 fps, onDraw pode ser chamado até 60 vezes por segundo. A 120 fps (em dispositivos com telas de 120 Hz) — até 120 vezes. Cada chamada deve ser concluída em aproximadamente 8–16 milissegundos. Durante animações ativas via ObjectAnimator ou ValueAnimator, a frequência é determinada pelo número de quadros da animação.

Qual é a diferença entre onDraw e dispatchDraw?

onDraw é responsável por desenhar o conteúdo da própria View. dispatchDraw é responsável por desenhar as Views filhas (em ViewGroup). dispatchDraw é chamado após onDraw e percorre recursivamente todos os elementos filhos. Para uma View comum (não ViewGroup), dispatchDraw é vazio.

Pode-se usar Canvas fora de onDraw?

Sim, Canvas pode ser criado para um Bitmap através de Canvas(bitmap) e desenhado em qualquer thread. Isso é usado para pré-renderizar gráficos complexos em segundo plano. No entanto, o Canvas passado para onDraw pertence ao sistema e só pode ser usado na thread de UI dentro do método onDraw.

Resumo

  • onDraw(Canvas) — um método chave da View para desenho personalizado usando Canvas API no Android
  • Ciclo de desenho consiste nas fases measure, layout e draw — onDraw é chamado na fase draw
  • Canvas API inclui os métodos drawCircle, drawRect, drawPath, drawBitmap, drawText e outros
  • invalidate() solicita redesenho da thread de UI, postInvalidate() de uma thread em segundo plano
  • Redesenho parcial via invalidate(Rect) otimiza a renderização atualizando apenas a região suja
  • Desempenho do onDraw é crítico: criar objetos dentro do método causa GC e quedas de quadros
  • Aceleração de hardware (desde API 11) acelera automaticamente as operações do Canvas através da GPU

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