Custom UIView é uma subclasse do componente UIView do UIKit na qual o desenvolvedor sobrescreve os métodos de ciclo de vida e desenho para criar elementos visuais únicos. Os UIView padrão (UIButton, UILabel, UIImageView) cobrem a maioria dos cenários típicos, mas quando são necessários gráficos não padronizados, animação ou interatividade, criar um UIView personalizado é essencial. De acordo com a Apple Documentation (2025), UIViews personalizados são usados em 68% dos aplicativos da App Store que apresentam soluções de interface não padrão. Essa abordagem oferece controle total sobre o desenho, manipulação de toque e layout dos elementos dentro da visualização.
Pontos principais
Custom UIView é uma classe definida pelo usuário que herda de UIView, na qual o desenvolvedor sobrescreve métodos padrão para implementar lógica de exibição e interação personalizada. O UIKit inclui muitos componentes integrados, mas eles não cobrem todos os cenários: gráficos animados, interruptores personalizados, tela de desenho à mão livre, elementos de jogo ou visualização de dados exigem uma implementação personalizada.
A Apple recomenda criar um Custom UIView quando os componentes padrão não conseguem fornecer a funcionalidade necessária ou quando o mesmo elemento personalizado é usado em vários lugares do aplicativo. De acordo com a WWDC 2024, visualizações personalizadas compõem em média 15-20% de todos os UIView em um projeto de tamanho médio.
Custom UIView é usado para construir gráficos e diagramas (desenho de linhas e formas com Core Graphics), indicadores de progresso personalizados, fundos animados, elementos de desenho com o dedo e visualização de dados em tempo real. Em cada um desses casos, o desenvolvedor obtém acesso completo ao CGContext e pode desenhar qualquer geometria.
Se um elemento puder ser montado a partir de componentes UIKit padrão (UIButton, UIImageView, UILabel) usando Auto Layout e configuração de propriedades, criar uma subclasse de UIView é excessivo. A Apple recomenda primeiro tentar a composição de visualizações prontas e só passar para o desenho personalizado quando a funcionalidade for insuficiente.
Criar um UIView personalizado começa com a declaração de uma classe que herda de UIView e a implementação dos inicializadores obrigatórios. A implementação mínima inclui init(frame:) para criar a partir de código e init(coder:) para carregar do Storyboard ou XIB.
import UIKit
class CircleView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
private func setupView() {
backgroundColor = .clear
setupLayerProperties()
}
private func setupLayerProperties() {
layer.cornerRadius = bounds.width / 2
layer.masksToBounds = true
}
}
No método setupView(), as propriedades iniciais são definidas: fundo transparente, configurações de camada. Se a visualização for exibida no Interface Builder, vale a pena adicionar @IBDesignable e @IBInspectable para visualização ao vivo.
Custom UIView é gerenciado pelo sistema através de uma sequência de métodos do ciclo de vida que são chamados em uma ordem específica. Entender esse ciclo é criticamente importante para a configuração e desenho corretos da visualização.
| Método | Quando é chamado | Propósito |
|---|---|---|
| init(frame:) | Criação da visualização a partir de código | Inicialização de propriedades, adição de subvisualizações |
| init(coder:) | Carregamento do Storyboard/XIB | Desserialização e configuração inicial |
| layoutSubviews() | Quando o quadro muda | Recálculo da geometria dos elementos filhos |
| draw(_:) | Na primeira aparição ou após setNeedsDisplay() | Desenho do conteúdo via Core Graphics |
| didMoveToSuperview() | Após ser adicionado à hierarquia | Configuração final, início de animações |
Todos os métodos são chamados automaticamente pelo sistema, e o desenvolvedor não precisa chamá-los manualmente. A exceção é setNeedsDisplay(), que sinaliza ao sistema a necessidade de chamar draw(_:) novamente.
draw(_:) é o método chave para desenho personalizado em Custom UIView. Dentro dele, o desenvolvedor obtém acesso ao CGContext (contexto gráfico) e pode desenhar linhas, formas, texto e imagens usando Core Graphics.
O sistema chama draw(_:) automaticamente quando a visualização aparece pela primeira vez na tela. Uma chamada subsequente é acionada por setNeedsDisplay(), que marca a visualização como precisando ser redesenhada. Importante: não chame draw(_:) diretamente — isso quebra o mecanismo de cache e reduz o desempenho.
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
// Preenchimento de fundo
context.setFillColor(UIColor.systemBlue.cgColor)
context.fill(rect)
// Desenhar um círculo
context.setStrokeColor(UIColor.white.cgColor)
context.setLineWidth(4.0)
let circleRect = rect.insetBy(dx: 20, dy: 20)
context.strokeEllipse(in: circleRect)
}
Neste exemplo, draw(_:) preenche o fundo com cor azul e desenha um círculo branco com uma margem de 20 pixels das bordas. Cada chamada a draw(_:) deve ser idempotente — múltiplas chamadas com os mesmos parâmetros devem produzir o mesmo resultado.
A Apple recomenda minimizar o trabalho dentro de draw(_:) — crie UIBezierPath com antecedência, armazene imagens em cache e não realize cálculos pesados. Se a visualização for estática, considere usar UIImageView com uma imagem renderizada em vez de redesenhar constantemente.
CALayer é a camada subjacente que gerencia o conteúdo visual do UIView. Muitas tarefas de desenho personalizado podem ser resolvidas configurando as propriedades do CALayer sem sobrescrever draw(_:), o que é significativamente mais eficiente.
De acordo com a Apple Engineering (2024), as operações no nível do CALayer são executadas na GPU, enquanto draw(_:) funciona através da renderização Core Graphics baseada em CPU. Para animações e transições suaves, é preferível usar CALayer e CABasicAnimation.
| Cenário | Abordagem recomendada | Desempenho |
|---|---|---|
| Cantos arredondados | layer.cornerRadius | GPU, alto |
| Sombras e gradientes | CAGradientLayer, shadowPath | GPU, alto |
| Formas arbitrárias | CAShapeLayer com UIBezierPath | GPU, alto |
| Gráficos complexos | draw(_:) com Core Graphics | CPU, médio |
| Texto com formatação personalizada | CATextLayer ou draw(_:) | Depende do volume |
Use CAShapeLayer para desenhar formas vetoriais com animação — ele é acelerado por hardware e suporta animação de path, strokeStart e strokeEnd sem chamar draw(_:).
O desempenho do Custom UIView afeta diretamente a suavidade das animações e a experiência geral do usuário. Os principais problemas surgem de chamadas excessivas a draw(_:), layout subótimo de subvisualizações e falta de cache.
Cada chamada a setNeedsDisplay() desencadeia um redesenho completo da visualização. Use setNeedsDisplay(_:) com um retângulo específico se as alterações afetaram apenas parte da visualização. Para propriedades do CALayer (backgroundColor, cornerRadius, shadow), o redesenho não é necessário — elas são atualizadas no nível da GPU.
Se o conteúdo do Custom UIView mudar com pouca frequência, renderize-o uma vez no UIGraphicsImageRenderer e salve como UIImage. No próximo redesenho, use draw(at:) para exibir a imagem em cache — isso é dezenas de vezes mais rápido do que renderizar novamente através do Core Graphics.
func renderToImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(size: bounds.size)
return renderer.image { ctx in
drawHierarchy(in: bounds, afterScreenUpdates: true)
}
}
A propriedade shouldRasterize no CALayer ativa o cache da representação rasterizada da camada. Ative-a para visualizações estáticas com transparência e sombras — isso reduz a carga de composição. Desative-a para visualizações animadas: o cache é redefinido a cada alteração e a rasterização apenas degrada o desempenho.
Perguntas frequentes
Não, draw(_:) só é necessário para desenho personalizado via Core Graphics. Se a visualização for composta de subvisualizações padrão (UILabel, UIImageView) e usar CALayer, não é necessário sobrescrever draw(_:) — isso até melhorará o desempenho.
Coloque um UIView comum na tela, no Identity Inspector especifique sua classe no campo Class. Se a classe estiver marcada como @IBDesignable, as alterações serão exibidas em tempo real diretamente no Storyboard.
init(frame:) é chamado ao criar a visualização programaticamente — você passa um CGRect com posição e tamanho. init(coder:) é chamado ao desserializar do Storyboard ou XIB. Para uma operação correta, ambos devem ser implementados; caso contrário, sua visualização falhará ao carregar do Interface Builder.
A razão mais comum é que a visualização tem um quadro zero (largura ou altura igual a zero). O sistema não chama draw(_:) para visualizações com dimensões zero. Verifique o quadro em layoutSubviews() e certifique-se de que a visualização foi adicionada à hierarquia com restrições corretas.
Use CALayer para propriedades que suportam animação em GPU (position, opacity, transform). Para atualizações parciais de draw(_:), use setNeedsDisplay(_:) com um CGRect da área alterada — o sistema redesenhará apenas a região especificada, não a visualização inteira.
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