Canvas no Android: o que é, classe Canvas e métodos draw

Autor: IT Sectr Publicado: 2026-07-21 Tempo de leitura: 7 min

Canvas no Android — é uma classe do pacote android.graphics que fornece uma API para renderização 2D em View. Canvas funciona como uma tela na qual o desenvolvedor desenha formas geométricas, texto, imagens e trajetos usando vários métodos draw*. De acordo com a Documentação para Desenvolvedores Android (2025), o Canvas é a principal ferramenta para renderização personalizada no Android e é usado junto com a classe Paint para definir estilos e cores. Cada chamada onDraw() recebe uma instância Canvas pronta, associada ao buffer de bitmap da view.

Pontos Principais

  • Canvas — uma classe para renderização 2D no Android, fornece métodos drawRect, drawCircle, drawText, drawBitmap e outros
  • Paint — uma classe que define o estilo de renderização: cor, espessura, preenchimento, efeitos (sombra, gradiente)
  • onDraw(Canvas) — o método de View onde toda a renderização ocorre através do Canvas recebido
  • Canvas.save() e restore() — gerenciamento da pilha de transformações para transformações aninhadas do sistema de coordenadas
  • Path — uma classe para construir contornos e curvas arbitrários, passada para drawPath(Path, Paint)

O que é Canvas no Android

Canvas — é a classe central de gráficos 2D no Android que fornece métodos para desenhar em um plano. Cada Canvas está vinculado a um Bitmap — uma área de memória onde os resultados das operações de desenho são registrados. Quando uma View é redesenhada, o sistema passa para onDraw() um Canvas já associado ao buffer dessa View.

O Canvas funciona em um sistema de coordenadas onde (0,0) é o canto superior esquerdo, o eixo X vai para a direita, o eixo Y para baixo. Todas as operações de desenho usam o estado atual do Canvas, incluindo a matriz de transformação, a área de recorte e o estilo Paint. De acordo com a Documentação Android (2025), a API Canvas inclui mais de 30 métodos draw* para diferentes tipos de primitivas gráficas.

Canvas e Aceleração por Hardware

Desde o Android 3.0 (API 11) o Canvas suporta aceleração por hardware através de DisplayList. No modo acelerado, as operações do Canvas são gravadas em uma DisplayList e depois executadas na GPU. Isso proporciona um ganho significativo de desempenho, mas impõe limitações: algumas operações do Canvas (clipPath com recorte não-Path) não são suportadas no modo acelerado.

Métodos básicos de renderização do Canvas

O Canvas fornece um conjunto de métodos para desenhar primitivas básicas. Cada método aceita parâmetros geométricos e um objeto Paint que define o estilo visual.

MétodoPropósitoExemplo
drawRect()Desenha um retângulocanvas.drawRect(10f, 10f, 100f, 100f, paint)
drawCircle()Desenha um círculocanvas.drawCircle(50f, 50f, 30f, paint)
drawLine()Desenha uma linhacanvas.drawLine(0f, 0f, 100f, 100f, paint)
drawText()Desenha textocanvas.drawText(“Hello”, 10f, 20f, paint)
drawBitmap()Desenha uma imagemcanvas.drawBitmap(bitmap, 0f, 0f, paint)
drawPath()Desenha um trajeto arbitráriocanvas.drawPath(path, paint)
drawOval()Desenha uma ovalcanvas.drawOval(rectF, paint)
drawArc()Desenha um arco ou setorcanvas.drawArc(rectF, 0f, 90f, true, paint)

Cada método pode ser chamado em qualquer ordem — o Canvas desenha na ordem das chamadas, sobrepondo novos elementos sobre os anteriores. Para composições complexas, é usada a técnica de renderização em múltiplas camadas com salvamento e restauração do estado do Canvas.

Classe Paint: configuração de estilos e efeitos

Paint — é a classe que define como o Canvas desenhará. Sem o Paint, os métodos do Canvas são inúteis — ele define cor, espessura da linha, estilo de preenchimento, tamanho do texto, efeitos (sombra, gradiente, desfoque) e modo de mesclagem.

O Paint possui propriedades-chave: color (cor), style (FILL, STROKE ou FILL_AND_STROKE), strokeWidth (espessura da linha), textSize (tamanho do texto), isAntiAlias (antialiasing), shader (gradiente ou imagem). Criar um objeto Paint é uma operação cara, portanto deve ser criado uma vez e reutilizado.

kotlin
private val fillPaint = Paint().apply {
    color = Color.parseColor("#FF6200EE")
    style = Paint.Style.FILL
    isAntiAlias = true
}

private val strokePaint = Paint().apply {
    color = Color.WHITE
    style = Paint.Style.STROKE
    strokeWidth = 4f
    isAntiAlias = true
}

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    canvas.drawCircle(100f, 100f, 80f, fillPaint)
    canvas.drawCircle(100f, 100f, 80f, strokePaint)
}

Neste exemplo, dois objetos Paint são usados: um para preencher o círculo com cor roxa, o segundo para o traçado branco. Separar preenchimento e traçado é uma prática padrão que permite controle flexível da aparência sem recriar objetos.

Shader e gradientes

Para preenchimentos gradientes, o Paint aceita um Shader — subclasses LinearGradient, RadialGradient, SweepGradient. O Shader é vinculado ao Paint através do método setShader() e define como a cor muda pela área de desenho.

Transformações do Canvas: translate, rotate, scale

O Canvas suporta transformações matriciais do sistema de coordenadas: translate() (translação), rotate() (rotação), scale() (escala) e skew() (inclinação). As transformações se acumulam: cada chamada subsequente é aplicada sobre as anteriores.

O gerenciamento da pilha de transformações é feito através de save() e restore(). save() salva o estado atual do Canvas (matriz, recorte) na pilha, restore() restaura o último estado salvo. Entre save() e restore(), transformações aninhadas podem ser aplicadas.

kotlin
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    canvas.save() // Save initial state
    canvas.translate(100f, 100f) // Translate origin

    // First square
    canvas.drawRect(0f, 0f, 50f, 50f, fillPaint)

    canvas.save() // Save after translate
    canvas.rotate(45f, 25f, 25f) // Rotate around square center

    // Rotated square
    canvas.drawRect(0f, 0f, 50f, 50f, strokePaint)
    canvas.restore() // Restore after rotate

    canvas.restore() // Restore initial state
}

Sempre use save() antes de iniciar transformações e restore() depois de concluí-las. Pares save/restore desbalanceados levam ao acúmulo de matriz e renderização incorreta de elementos subsequentes.

Canvas com Bitmap e Path para gráficos complexos

Para gráficos complexos, o Canvas é combinado com Bitmap e Path. Bitmap é usado para carregar imagens e armazenar em cache quadros renderizados. Path é usado para construir curvas Bezier arbitrárias, polígonos e contornos complexos.

Buffer Bitmap fora da tela

A técnica de renderização fora da tela: um Bitmap é criado, uma cena complexa é desenhada nele através de um Canvas separado, e então o Bitmap finalizado é exibido em onDraw() via drawBitmap(). Isso permite atualizar gráficos complexos sem redesenho completo a cada quadro.

kotlin
private var offscreenBitmap: Bitmap? = null
private var offscreenCanvas: Canvas? = null

fun buildOffscreenScene(width: Int, height: Int) {
    offscreenBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    offscreenCanvas = Canvas(offscreenBitmap)

    // Render scene once
    offscreenCanvas!!.drawColor(Color.WHITE)
    drawGrid(offscreenCanvas!!)
    drawComplexShape(offscreenCanvas!!)
}

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    offscreenBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) }
}

Path é usado para construir contornos complexos: curvas Bezier (quadTo, cubicTo), arcos (arcTo), linhas (lineTo). Path pode ser fechado (close()) para formas preenchidas ou aberto para linhas. O método principal drawPath() combina Path e Paint para a renderização final.

Otimização da renderização do Canvas

O desempenho da renderização do Canvas afeta diretamente os FPS do aplicativo. Os principais problemas: alocações excessivas em onDraw(), chamadas frequentes a invalidate() e uso subótimo da Aceleração por Hardware.

Crie objetos fora de onDraw()

Paint, Path, Rect, RectF e outros objetos devem ser criados uma vez no inicializador ou método setup(). Cada alocação em onDraw() gera pressão no coletor de lixo, causando microlags. A exceção são objetos static ou companion object para objetos imutáveis.

Use clipRect() para limitar a área

Se a maior parte da View estiver oculta fora da área visível (por exemplo, em ScrollView), use canvas.clipRect() para limitar a renderização. A Aceleração por Hardware neste caso otimiza adicionalmente o recorte de pixels invisíveis.

kotlin
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    // Clip to visible area
    canvas.save()
    canvas.clipRect(scrollX, scrollY, scrollX + width, scrollY + height)

    // Render large scene
    renderScene(canvas)
    canvas.restore()
}

Use View.setLayerType() com LAYER_TYPE_HARDWARE para Views com gráficos Canvas complexos que são atualizados raramente. Para animações atualizadas com frequência, use LAYER_TYPE_NONE para evitar atualizações caras da camada de hardware. Faça perfilamento usando GPU Profile Rendering e Android Studio Profiler.

Perguntas Frequentes

Posso criar um Canvas sem uma View?

Sim, você pode criar Canvas(Bitmap) — um construtor que aceita um Bitmap. Isso é usado para renderização fora da tela: você desenha em um Bitmap e depois o exibe via drawBitmap(). O Canvas também pode ser criado a partir de Surface (para SurfaceView) ou através de Picture.

Qual a diferença entre Canvas e SurfaceView?

Canvas — é uma API para desenhar em View na thread da UI. SurfaceView — é um Surface separado que pode ser atualizado de uma thread em segundo plano através de seu próprio Canvas (lockCanvas() / unlockCanvasAndPost()). SurfaceView é preferível para jogos e vídeo.

Por que o Canvas não desenha após a transformação?

A razão mais comum são pares desbalanceados de save() e restore(). Se após uma transformação (translate, rotate) restore() não for chamado, o Canvas permanece em um sistema de coordenadas modificado, e os elementos subsequentes são desenhados com deslocamento. Verifique seus pares save()/restore().

Como desenhar texto centralizado no Canvas?

Use Paint.setTextAlign(Paint.Align.CENTER) para centralização horizontal e Paint.getTextBounds() ou Paint.descent() / ascent() para vertical. Centralização: canvas.drawText(texto, centerX, centerY - (ascent + descent) / 2, paint).

O Canvas suporta animação?

O Canvas por si só não anima — ele apenas desenha o estado atual. A animação é alcançada através de chamadas sequenciais a invalidate() (ou postInvalidateOnAnimation()), desenhando um novo quadro em onDraw() a cada vez. Para animações suaves, use ValueAnimator ou Choreographer para sincronizar com Vsync.

Resumo

  • Canvas — a classe central de renderização 2D no Android, fornece métodos draw* para desenhar primitivas, texto e imagens
  • Paint — define o estilo visual (cor, espessura, preenchimento, shaders); criado uma vez e reutilizado
  • save() / restore() — gerenciamento da pilha de transformações; cada transformação deve estar em um par save/restore
  • Path — construção de contornos arbitrários e curvas Bezier para gráficos vetoriais complexos
  • Offscreen Bitmap — técnica de cache de cenas complexas via Canvas(Bitmap) para reduzir a carga em onDraw()
  • Aceleração por Hardware — aceleração GPU do Canvas desde Android 3.0, impõe limitações em algumas operações (clipPath)
  • Perfilamento — GPU Profile Rendering e Android Studio Profiler são obrigatórios para encontrar gargalos em onDraw()

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