Views personalizadas e desenho no desenvolvimento móvel: essência, quais APIs e como funciona

Autor: IT Sectr Publicado: 2026-08-01 Tempo de leitura: 11 min

As views personalizadas são a base da interface única de qualquer aplicativo móvel. As views personalizadas em aplicativos móveis permitem criar gráficos, animações e elementos próprios não disponíveis em componentes padrão. De acordo com Apple Developer, 2025, o drawRect continua sendo o método principal de desenho personalizado no desenvolvimento móvel iOS. No Android, o onDraw com Canvas desempenha o mesmo papel, e no Flutter — o CustomPainter.

Principais pontos

  • Views personalizadas — componentes definidos pelo usuário com lógica própria de desenho, tamanho e comportamento em aplicativos móveis.
  • drawRect — método UIView no iOS para desenho personalizado via Core Graphics e CGContext.
  • onDraw — método View no Android para desenho via Canvas e Paint com o sistema de medição onMeasure.
  • CustomPainter — classe Flutter para desenho no Canvas com os métodos paint e shouldRepaint.
  • Medição — processo de determinar as dimensões da View via sizeThatFits no iOS, onMeasure no Android e computeDryLayout no Flutter.

O que são views personalizadas e por que são necessárias em aplicativos móveis

Views personalizadas são componentes de interface definidos pelo usuário que sobrescrevem os métodos padrão de desenho e medição para criar gráficos únicos. Gráficos, animações, diagramas, elementos de chat personalizados e máscaras AR — são cenários típicos de uso de views personalizadas em aplicativos móveis. Os componentes de UI padrão (Button, TextView, Label) cobrem 80% das tarefas, mas os 20% restantes exigem controle total sobre o desenho no desenvolvimento móvel. O desenho no desenvolvimento móvel é uma habilidade que diferencia um desenvolvedor júnior de um sênior.

Quando as views personalizadas são justificadas

Views personalizadas em aplicativos móveis são necessárias para gráficos 2D únicos, animações complexas, gráficos estatísticos e visualização de dados. Se o UIKit padrão não fornece o elemento necessário — cria-se uma view personalizada. Em aplicativos móveis, views personalizadas são usadas para barras de progresso, botões personalizados, preenchimentos gradientes, ícones animados e telas para desenho com o dedo. É importante não abusar — para estilos simples, basta configurar os componentes padrão através da API de aparência.

Views personalizadas no iOS: drawRect e Core Graphics

No iOS, views personalizadas são criadas herdando de UIView e sobrescrevendo o método drawRect. drawRect é chamado na primeira renderização e após cada chamada setNeedsDisplay(). Dentro do drawRect, o desenvolvedor obtém um CGContext via UIGraphicsGetCurrentContext() — uma tela para linhas, formas, gradientes e texto. Core Graphics (Quartz 2D) é um motor de renderização de baixo nível na CPU que dá controle total sobre cada pixel. UIBezierPath é um wrapper conveniente para criar caminhos com sintaxe concisa.

swift
class CircleView: UIView {
    private var fillColor: UIColor = .systemBlue

    override func drawRect(_ rect: CGRect) {
        guard let ctx = UIGraphicsGetCurrentContext() else { return }
        ctx.setFillColor(fillColor.cgColor)
        ctx.addEllipse(in: bounds.insetBy(dx: 4, dy: 4))
        ctx.drawPath(using: .fill)
    }

    func updateColor(_ newColor: UIColor) {
        fillColor = newColor
        setNeedsDisplay()
    }
}

Core Graphics: CGContext, CGGradient e transformações

Core Graphics fornece CGContext — uma tela para todas as operações de desenho. CGGradient cria gradientes lineares e radiais com suporte a CGColorSpace (sRGB, Display P3). As transformações são realizadas via CGAffineTransform — uma matriz 3x3 para rotação, escala e translação. CGContextTranslateCTM, CGContextRotateCTM e CGContextScaleCTM modificam o sistema de coordenadas. Core Graphics funciona na CPU, então gráficos complexos podem sobrecarregar o processador — use Metal para aceleração GPU.

UIBezierPath para criar formas

UIBezierPath é um wrapper orientado a objetos sobre CGPath. O método addArc(withCenter:radius:startAngle:endAngle:clockwise:) cria arcos e círculos, addCurve cria curvas Bézier. Os caminhos suportam operações de união, interseção e subtração via addClip. UIBezierPath é conveniente para máscaras personalizadas (maskView), caminhos de recorte e formas complexas — estrelas, corações, ícones personalizados.

Views personalizadas no Android: onDraw e Canvas

No Android, uma view personalizada estende View com onDraw(Canvas) sobrescrito. Canvas contém todos os métodos de desenho no desenvolvimento móvel: drawCircle, drawRect, drawLine, drawText, drawBitmap, drawPath e drawRoundRect. Paint configura os parâmetros — cor, espessura da linha, estilo (FILL, STROKE, FILL_AND_STROKE), suavização (isAntiAlias) e tamanho do texto. onDraw é chamado a cada invalidate() e não deve conter operações pesadas — todos os cálculos são armazenados em cache.

kotlin
class CustomCircleView(context: Context, attrs: AttributeSet?)
    : View(context, attrs) {

    private val paint = Paint().apply {
        style = Paint.Style.FILL
        color = Color.BLUE
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val cx = width / 2f
        val cy = height / 2f
        val radius = minOf(cx, cy) - 4f
        canvas.drawCircle(cx, cy, radius, paint)
    }
}

Path e animações no Android

Path no Android é o equivalente ao UIBezierPath: addCircle, addRect, addOval, lineTo, cubicTo e quadTo. PathMeasure calcula o comprimento do caminho e as coordenadas em qualquer ponto — útil para animar o movimento de um objeto ao longo de um caminho. Para animações, use ValueAnimator com invalidate() no callback. O animador pode mudar cor, raio, posição — qualquer propriedade que afete o desenho. Views personalizadas no Android também suportam StateListDrawable e animated-vector para animação via XML.

Shader e gradientes no Canvas

Gradientes no Android são definidos via Shader — LinearGradient, RadialGradient e SweepGradient. Shader é atribuído ao Paint via paint.setShader(shader). LinearGradient gera um gradiente linear entre dois pontos com posições de cor opcionais. RadialGradient — radial do centro para as bordas. SweepGradient — cônico em torno de um ponto central. Shader.TileMode (CLAMP, REPEAT, MIRROR) define o comportamento além dos limites da área.

CustomPainter no Flutter: desenho no Canvas

Flutter usa CustomPainter — uma classe com os métodos paint(Canvas canvas, Size size) e shouldRepaint. Canvas no Flutter fornece os mesmos métodos que no Android: drawCircle, drawRect, drawLine, drawPath, drawParagraph e drawImage. Paint no Flutter configura cor, espessura, estilo e suavização. Flutter não usa drawRect ou onDraw — todo o desenho é feito via CustomPainter, incorporado no widget CustomPaint.

dart
class CirclePainter extends CustomPainter {
  final Color color;

  CirclePainter({required this.color});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    final radius = size.shortestSide / 2 - 4;
    canvas.drawCircle(size.center(Offset.zero), radius, paint);
  }

  @override
  bool shouldRepaint(CirclePainter oldDelegate) =>
    oldDelegate.color != color;
}

shouldRepaint e RepaintBoundary

shouldRepaint determina se o CustomPainter precisa redesenhar. Retorne true apenas quando os dados que afetam a renderização mudarem — cor, tamanho, dados do gráfico. RepaintBoundary isola o redesenho em uma camada separada — use para widgets que raramente mudam. Flutter não tem setNeedsDisplay ou invalidate — o redesenho é acionado via setState ou ValueNotifier com escuta de alterações.

Gradientes e transformações no Flutter

Flutter suporta LinearGradient, RadialGradient e SweepGradient — os mesmos tipos que no Android. Gradient cria um Shader para Paint via createShader(Rect bounds). As transformações são realizadas via canvas.rotate, canvas.scale, canvas.translate e canvas.skew. Flutter usa uma matriz de transformação 4x4 (Matrix4) para o widget Transform. Animações de desenho no Flutter são feitas com AnimationController junto com setState para redesenhar o CustomPainter.

Medição de views personalizadas: métodos sizeThatFits, onMeasure e computeDryLayout

A medição correta de views personalizadas é a base do comportamento previsível da interface. No iOS, o tamanho da View é determinado via sizeThatFits e intrinsicContentSize. sizeThatFits retorna o tamanho ideal para as restrições dadas. intrinsicContentSize — o tamanho natural do conteúdo sem restrições externas. No Android, a medição é implementada no onMeasure com parâmetros MeasureSpec (UNSPECIFIED, EXACTLY, AT_MOST). No Flutter, o tamanho é passado para paint(Canvas, Size) e pode ser calculado via computeDryLayout ou LayoutBuilder.

sizeThatFits e intrinsicContentSize no iOS

intrinsicContentSize retorna um CGSize — o tamanho natural da View baseado em seu conteúdo. setContentHuggingPriority e setContentCompressionResistancePriority controlam o comportamento durante alongamento e compressão. sizeThatFits é chamado pelo sistema para calcular o tamanho no Auto Layout. Para views personalizadas, sobrescreva intrinsicContentSize se seu componente tiver um tamanho natural — por exemplo, um círculo deve ser sempre 100x100.

onMeasure e MeasureSpec no Android

onMeasure aceita widthMeasureSpec e heightMeasureSpec. MeasureSpec contém modo e tamanho: UNSPECIFIED (sem restrições, a View escolhe seu tamanho), EXACTLY (tamanho exato do pai), AT_MOST (tamanho máximo). setMeasuredDimension(width, height) salva o resultado da medição. Ao alterar dados, chame requestLayout() para remensurar. ViewGroups aninhados exigem sobrescrita de onLayout para organizar os elementos filhos.

PlataformaMétodo de mediçãoChamada na alteraçãoRetorno
iOSsizeThatFits / intrinsicContentSizesetNeedsLayout / invalidateIntrinsicContentSizeCGSize
AndroidonMeasure / setMeasuredDimensionrequestLayout / invalidatevoid (salva tamanho)
FluttercomputeDryLayoutsetState / LayoutBuilderSize

computeDryLayout no Flutter

computeDryLayout é um método RenderObject para calcular o tamanho sem um ciclo completo de layout. LayoutBuilder.getSize — uma alternativa para obter o espaço disponível no método build. No Flutter, o tamanho da tela é passado para paint como Size e não requer medição separada — CustomPainter desenha dentro dos limites passados. No entanto, para RenderObjects personalizados, é necessário sobrescrever performLayout e computeDryLayout.

Perguntas frequentes

O que é drawRect no iOS e quando é chamado?

drawRect é um método UIView para desenho personalizado via Core Graphics. É chamado na primeira renderização da View e após cada chamada setNeedsDisplay(). Use CGContext dentro do drawRect para linhas, formas e texto.

Como desenhar no Android usando Canvas?

Crie uma classe estendendo View, sobrescreva onDraw(Canvas canvas) e use a API Canvas: drawCircle, drawRect, drawPath. Paint configura cor, espessura e estilo. Para atualizar, chame invalidate().

O que é CustomPainter no Flutter?

CustomPainter é uma classe Flutter para desenho personalizado no Canvas. Implemente os métodos paint(Canvas, Size) e shouldRepaint. É colocado através do widget CustomPaint. Flutter não tem drawRect — todo desenho é feito via CustomPainter.

Como medir o tamanho de uma view personalizada?

No iOS use sizeThatFits e intrinsicContentSize. No Android — onMeasure com MeasureSpec. No Flutter, o tamanho é passado para paint(Canvas, Size) ou calculado via computeDryLayout. Cada plataforma usa seu próprio método de medição.

Quando usar views personalizadas em vez de componentes padrão?

Views personalizadas são necessárias para gráficos únicos, animações, gráficos e elementos que não podem ser implementados com UIKit ou View padrão. Para estilos simples, basta configurar os componentes padrão — não complique a arquitetura desnecessariamente.

Resumo

  • Views personalizadas — base de interfaces únicas para gráficos, animações e elementos não padrão em aplicativos móveis.
  • drawRect — método iOS para desenho via Core Graphics com CGContext e UIBezierPath.
  • onDraw — método Android para desenho via Canvas e Paint com suporte a Path e Shader.
  • CustomPainter — classe Flutter para desenho no Canvas com shouldRepaint e RepaintBoundary.
  • Medição — validação de tamanhos via sizeThatFits (iOS), onMeasure (Android) e computeDryLayout (Flutter).
  • O desenho no desenvolvimento móvel segue um padrão unificado em todas as plataformas: obter um contexto, configurar estilos e desenhar primitivas.
  • Armazene em cache objetos de desenho (Paint, Path) — não os crie dentro de drawRect, onDraw ou paint para desempenho estável.

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