CGContext é o principal objeto do Core Graphics para executar comandos de desenho 2D no iOS e macOS. Ele representa um contexto gráfico que armazena o estado atual: cor de preenchimento, espessura da linha, transformação, área de corte e fontes. Todas as operações de desenho — linhas, retângulos, texto, imagens — são realizadas através do CGContext. De acordo com Apple Developer Documentation, 2026, CGContext é a base de todos os gráficos raster e vetoriais no ecossistema Apple.
Principais Pontos
CGContext é um tipo opaco (opaque type) do framework Core Graphics que representa um ambiente para executar comandos de renderização 2D. Ele gerencia a pilha de estados, o espaço de cor atual, a transformação de coordenadas e a área de corte. CGContext é o único objeto com o qual todas as funções de desenho Quartz 2D interagem — qualquer operação gráfica passa por ele.
CGContext existe em várias variedades dependendo da finalidade: bitmap context para trabalhar com imagens raster na memória, PDF context para gerar documentos PDF, window context para desenho na tela (fornecido pelo UIView no draw(_:)). Os desenvolvedores iOS trabalham mais frequentemente com um contexto obtido de UIGraphicsGetCurrentContext() dentro do método draw(_:) ou de UIGraphicsBeginImageContextWithOptions para renderização offline.
O contexto aplica todas as configurações através de uma pilha de estados — o desenvolvedor pode salvar o estado atual (saveGState), modificar parâmetros e restaurar o estado anterior (restoreGState). Isso é criticamente importante ao desenhar cenas complexas onde diferentes elementos exigem diferentes cores, espessuras de linha e transformações. De acordo com a Apple WWDC 2023, o uso adequado da pilha de estados melhora a legibilidade do código e previne artefatos visuais.
CGContextSaveGState coloca uma cópia do estado atual do contexto na pilha. Este estado inclui todas as configurações: cores, espessura da linha, transformação, sombras, área de corte, fontes. Após modificar os parâmetros, a chamada CGContextRestoreGState retorna o contexto ao estado salvo, desfazendo todas as alterações intermediárias. A pilha pode conter até 32 estados no iOS.
Ao desenhar grupos de elementos com estilos diferentes (por exemplo, setores de um gráfico multicolorido), a pilha de estados elimina a necessidade de lembrar e restaurar manualmente cada parâmetro. Sem saveGState/restoreGState, o desenvolvedor teria que redefinir a cor, a sombra e a transformação após cada elemento. Usar a pilha reduz o código e previne erros de restauração.
É importante manter um equilíbrio de salvamentos e restaurações — cada saveGState deve ter um restoreGState correspondente. Quebrar o equilíbrio causa vazamento de estados ou restauração prematura, resultando em renderização imprevisível. O analisador estático do Xcode não verifica o equilíbrio da pilha do CGContext, portanto a correção é responsabilidade do desenvolvedor. Recomenda-se agrupar os pares em blocos do/finally.
override func draw(_ rect: CGRect) {
guard let ctx = UIGraphicsGetCurrentContext() else { return }
ctx.saveGState()
ctx.setStrokeColor(UIColor.red.cgColor)
ctx.setLineWidth(3)
ctx.addRect(CGRect(x: 50, y: 50, width: 200, height: 100))
ctx.strokePath()
ctx.restoreGState()
}
CGContextSetFillColorWithColor define a cor de preenchimento para operações subsequentes. A cor é passada como CGColorRef, que contém informações sobre o espaço de cor e os componentes da cor. CGContextSetStrokeColorWithColor funciona de forma similar para a cor do traço. A Apple recomenda armazenar em cache os valores CGColorRef usados com frequência para melhorar o desempenho.
CGContextDrawLinearGradient desenha um gradiente linear entre dois pontos com cores especificadas. CGContextDrawRadialGradient cria um gradiente radial que faz a transição de um círculo para outro. Para trabalhar com gradientes, primeiro é criado um objeto CGGradientRef contendo uma matriz de cores e posições de parada. Gradientes no CGContext suportam espaços de cor RGB e Escala de Cinza.
Preencher uma área com um gradiente requer primeiro definir uma área de corte. Sem clip, o gradiente preencherá todo o contexto, não apenas a forma desejada. O padrão típico: adicionar um caminho ao contexto, chamar clip para restringir a área, depois desenhar o gradiente. Este padrão é usado em todas as aplicações que exigem preenchimentos gradientes de formas complexas, desde botões até fundos.
| Função | Finalidade | Espaço de Cor |
|---|---|---|
| setFillColor | Define a cor de preenchimento | Qualquer (via CGColor) |
| setStrokeColor | Define a cor do traço | Qualquer (via CGColor) |
| drawLinearGradient | Desenha um gradiente linear | RGB ou Escala de Cinza |
| drawRadialGradient | Desenha um gradiente radial | RGB ou Escala de Cinza |
CGContextAddPath adiciona um CGPathRef previamente criado ao contexto para renderização subsequente. Após adicionar um caminho, ele pode ser traçado (strokePath), preenchido (fillPath) ou ambos. CGContextBeginPath inicia um novo caminho, limpando o anterior. O contexto suporta apenas um caminho ativo por vez.
CGContextMoveToPoint move o ponto atual do contorno para as coordenadas especificadas. CGContextAddLineToPoint desenha uma linha reta do ponto atual até o ponto dado. CGContextAddCurveToPoint adiciona uma curva cúbica de Bézier, CGContextAddQuadCurveToPoint adiciona uma quadrática. CGContextClosePath fecha o contorno com uma linha reta entre o último e o primeiro ponto.
Ao contrário do UIBezierPath, onde todos esses métodos são chamados no objeto de caminho, no CGContext eles são chamados diretamente no contexto. Esta diferença importa ao escolher uma abordagem: UIBezierPath é mais conveniente para reutilizar caminhos, CGContext é melhor para desenho único com sobrecarga mínima. CGContext também suporta linhas tracejadas via CGContextSetLineDash, extremidades flexíveis via CGContextSetLineCap e junções via CGContextSetLineJoin.
let ctx = UIGraphicsGetCurrentContext()!
ctx.beginPath()
ctx.moveTo(x: 50, y: 100)
ctx.addLineTo(x: 200, y: 100)
ctx.addCurveTo(x1: 250, y1: 50, x2: 300, y2: 150, x3: 350, y3: 100)
ctx.setStrokeColor(UIColor.blue.cgColor)
ctx.setLineWidth(5)
ctx.strokePath()
CGContextClip restringe a área de desenho ao caminho atual. Todas as operações de desenho subsequentes serão visíveis apenas dentro desta área. Este é o mecanismo básico para mascaramento, arredondamento de cantos e criação de limites personalizados de elementos. A área de corte também é salva e restaurada via saveGState/restoreGState.
CGContextTranslateCTM desloca a origem do sistema de coordenadas do contexto. CGContextScaleCTM escala os eixos X e Y. CGContextRotateCTM gira o sistema de coordenadas em torno da origem atual. As transformações acumulam-se — cada subsequente é aplicada em relação ao sistema de coordenadas atual. Transformações compostas (translação + rotação + escala) são usadas para animação e posicionamento de elementos.
Combinar corte e transformações fornece capacidades poderosas: você pode desenhar uma máscara complexa através do corte e depois aplicar uma transformação a todo o conteúdo. Um exemplo típico é exibir parte de uma imagem em ângulo com cantos arredondados. A ordem das operações importa: primeiro defina a área de corte, depois aplique a transformação, depois desenhe o conteúdo. A Apple recomenda minimizar as alterações da CTM (Matriz de Transformação Atual) no loop de desenho.
override func draw(_ rect: CGRect) {
guard let ctx = UIGraphicsGetCurrentContext() else { return }
ctx.saveGState()
// clipping region - circle
ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 200, height: 200))
ctx.clip()
// content transformation
ctx.translateBy(x: 150, y: 150)
ctx.rotate(by: .pi / 4)
ctx.translateBy(x: -150, y: -150)
UIImage(named: "photo")?.draw(at: CGPoint(x: 50, y: 50))
ctx.restoreGState()
}
Vamos ver um exemplo completo de criação de um gráfico gradiente usando CGContext. O gráfico inclui três setores de diferentes cores com preenchimentos gradientes e rótulos de texto. O código demonstra a combinação de saveGState, clip, gradientes e renderização de texto em um único contexto.
class PieChartView: UIView {
private struct Slice {
let color: UIColor
let value: CGFloat
let label: String
}
override func draw(_ rect: CGRect) {
guard let ctx = UIGraphicsGetCurrentContext() else { return }
let slices = [
Slice(color: .systemRed, value: 0.4, label: "iOS"),
Slice(color: .systemGreen, value: 0.35, label: "Android"),
Slice(color: .systemBlue, value: 0.25, label: "Other")
]
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let radius = bounds.width * 0.35
var startAngle: CGFloat = -.pi / 2
for slice in slices {
let endAngle = startAngle + .pi * 2 * slice.value
ctx.saveGState()
ctx.moveTo(x: center.x, y: center.y)
ctx.addArc(center: center, radius: radius,
startAngle: startAngle, endAngle: endAngle, clockwise: false)
ctx.closePath()
ctx.setFillColor(slice.color.cgColor)
ctx.fillPath()
// text label
let midAngle = startAngle + endAngle / 2
let labelPos = CGPoint(
x: center.x + radius * 0.7 * cos(midAngle),
y: center.y + radius * 0.7 * sin(midAngle)
)
slice.label.draw(at: labelPos, withAttributes: [
.foregroundColor: UIColor.white,
.font: UIFont.boldSystemFont(ofSize: 14)
])
ctx.restoreGState()
startAngle = endAngle
}
}
}
Neste exemplo, cada setor do gráfico é desenhado em seu próprio bloco saveGState/restoreGState. Esta abordagem garante que as configurações de cor e caminho de um setor não afetem os outros. O método addArc cria um arco do ângulo inicial ao final, e closePath fecha o setor em direção ao centro. O texto do rótulo é colocado no ângulo médio do setor usando as funções trigonométricas cos e sin para cálculo da posição.
Para melhorar o desempenho durante redesenho frequente, recomenda-se armazenar em cache os cálculos de ângulos e posições em um array separado. CGContext executa todas as operações na CPU, portanto cenas complexas com dezenas de setores podem exigir otimização — por exemplo, pré-renderização em CGLayer ou uso de Metal para aceleração GPU. Para a maioria das tarefas de UI com 5–10 elementos, o desempenho do CGContext permanece aceitável.
Perguntas Frequentes
Chame UIGraphicsGetCurrentContext() dentro do método draw(_:) do UIView ou dentro de um bloco UIGraphicsBeginImageContextWithOptions. Para camadas CALayer, use o método draw(in:) do CALayerDelegate, que recebe um contexto pronto.
fillPath preenche o interior do caminho atual com a cor de setFillColor. strokePath desenha uma linha ao longo do caminho com os parâmetros de setStrokeColor, setLineWidth e setLineCap. Ambas as operações são executadas sequencialmente: primeiro preenchimento, depois traço se necessário.
Bitmap CGContext é um contexto criado via CGBitmapContextCreate que desenha em um buffer de memória em vez da tela. É usado para geração de imagens em segundo plano, processamento de gráficos sem exibição e criação de texturas para Metal ou OpenGL.
Core Graphics não fornece um método para redefinir todas as configurações. Use saveGState antes das alterações e restoreGState para retornar ao estado original. Alternativamente, crie um novo contexto com os mesmos parâmetros.
Antes de chamar drawLinearGradient, defina a área de corte via clip no caminho desejado. Sem clip, o gradiente preenche todo o contexto. Ordem: addPath → clip → drawLinearGradient — garante o gradiente dentro da forma.
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