CGContext es el objeto principal de Core Graphics para ejecutar comandos de dibujo 2D en iOS y macOS. Representa un contexto gráfico que almacena el estado actual: color de relleno, grosor de línea, transformación, área de recorte y fuentes. Todas las operaciones de dibujo — líneas, rectángulos, texto, imágenes — se realizan a través de CGContext. Según Apple Developer Documentation, 2026, CGContext es la base de todos los gráficos rasterizados y vectoriales en el ecosistema Apple.
Puntos Clave
CGContext es un tipo opaco del framework Core Graphics que representa un entorno para ejecutar comandos de renderizado 2D. Gestiona la pila de estados, el espacio de color actual, la transformación de coordenadas y el área de recorte. CGContext es el único objeto con el que interactúan todas las funciones de dibujo de Quartz 2D — cualquier operación gráfica pasa a través de él.
CGContext existe en varias variedades según su propósito: bitmap context para trabajar con imágenes rasterizadas en memoria, PDF context para generar documentos PDF, window context para dibujo en pantalla (proporcionado por UIView en draw(_:)). Los desarrolladores de iOS trabajan más a menudo con un contexto obtenido de UIGraphicsGetCurrentContext() dentro del método draw(_:) o de UIGraphicsBeginImageContextWithOptions para renderizado sin conexión.
El contexto aplica toda la configuración a través de una pila de estados — el desarrollador puede guardar el estado actual (saveGState), modificar parámetros y restaurar el estado anterior (restoreGState). Esto es críticamente importante al dibujar escenas complejas donde diferentes elementos requieren diferentes colores, grosores de línea y transformaciones. Según Apple WWDC 2023, el uso correcto de la pila de estados mejora la legibilidad del código y previene artefactos visuales.
CGContextSaveGState coloca una copia del estado actual del contexto en la pila. Este estado incluye toda la configuración: colores, grosor de línea, transformación, sombras, área de recorte, fuentes. Después de modificar los parámetros, la llamada a CGContextRestoreGState devuelve el contexto al estado guardado, deshaciendo todos los cambios intermedios. La pila puede contener hasta 32 estados en iOS.
Al dibujar grupos de elementos con diferentes estilos (por ejemplo, sectores de un gráfico multicolor), la pila de estados elimina la necesidad de recordar y restaurar manualmente cada parámetro. Sin saveGState/restoreGState, el desarrollador tendría que restablecer el color, la sombra y la transformación después de cada elemento. Usar la pila reduce el código y previene errores de restauración.
Es importante mantener un equilibrio de guardados y restauraciones — cada saveGState debe tener su correspondiente restoreGState. Romper el equilibrio provoca fugas de estado o restauración prematura, causando renderizado impredecible. El analizador estático de Xcode no verifica el equilibrio de la pila de CGContext, por lo que la corrección es responsabilidad del desarrollador. Se recomienda agrupar los pares en bloques 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 establece el color de relleno para operaciones posteriores. El color se pasa como CGColorRef, que contiene información sobre el espacio de color y los componentes del color. CGContextSetStrokeColorWithColor funciona de manera similar para el color de trazo. Apple recomienda almacenar en caché los valores CGColorRef utilizados con frecuencia para mejorar el rendimiento.
CGContextDrawLinearGradient dibuja un degradado lineal entre dos puntos con colores especificados. CGContextDrawRadialGradient crea un degradado radial que transiciona de un círculo a otro. Para trabajar con degradados, primero se crea un objeto CGGradientRef que contiene una matriz de colores y posiciones de parada. Los degradados en CGContext admiten espacios de color RGB y Escala de Grises.
Rellenar un área con un degradado requiere establecer un área de recorte primero. Sin clip, el degradado llenará todo el contexto, no solo la forma deseada. El patrón típico: agregar un trayecto al contexto, llamar a clip para restringir el área, luego dibujar el degradado. Este patrón se usa en todas las aplicaciones que requieren rellenos degradados de formas complejas, desde botones hasta fondos.
| Función | Propósito | Espacio de Color |
|---|---|---|
| setFillColor | Establece el color de relleno | Cualquiera (mediante CGColor) |
| setStrokeColor | Establece el color de trazo | Cualquiera (mediante CGColor) |
| drawLinearGradient | Dibuja un degradado lineal | RGB o Escala de Grises |
| drawRadialGradient | Dibuja un degradado radial | RGB o Escala de Grises |
CGContextAddPath agrega un CGPathRef previamente creado al contexto para su posterior renderizado. Después de agregar un trayecto, se puede trazar (strokePath), rellenar (fillPath) o ambas. CGContextBeginPath inicia un nuevo trayecto, limpiando el anterior. El contexto admite solo un trayecto activo a la vez.
CGContextMoveToPoint mueve el punto actual del contorno a las coordenadas especificadas. CGContextAddLineToPoint dibuja una línea recta desde el punto actual hasta el punto dado. CGContextAddCurveToPoint agrega una curva cúbica de Bézier, CGContextAddQuadCurveToPoint agrega una cuadrática. CGContextClosePath cierra el contorno con una línea recta entre el último y el primer punto.
A diferencia de UIBezierPath, donde todos estos métodos se llaman en el objeto de trayecto, en CGContext se llaman directamente en el contexto. Esta diferencia importa al elegir un enfoque: UIBezierPath es más conveniente para reutilizar trayectos, CGContext es mejor para dibujo único con sobrecarga mínima. CGContext también admite líneas discontinuas mediante CGContextSetLineDash, extremos flexibles mediante CGContextSetLineCap y uniones mediante 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 el área de dibujo al trayecto actual. Todas las operaciones de dibujo posteriores serán visibles solo dentro de esta área. Este es el mecanismo básico para enmascarar, redondear esquinas y crear límites personalizados de elementos. El área de recorte también se guarda y restaura mediante saveGState/restoreGState.
CGContextTranslateCTM desplaza el origen del sistema de coordenadas del contexto. CGContextScaleCTM escala los ejes X e Y. CGContextRotateCTM rota el sistema de coordenadas alrededor del origen actual. Las transformaciones se acumulan — cada una posterior se aplica en relación al sistema de coordenadas actual. Las transformaciones compuestas (traslación + rotación + escala) se utilizan para animación y posicionamiento de elementos.
Combinar recorte y transformaciones proporciona capacidades potentes: puedes dibujar una máscara compleja mediante recorte y luego aplicar una transformación a todo el contenido. Un ejemplo típico es mostrar parte de una imagen en ángulo con esquinas redondeadas. El orden de las operaciones importa: primero establecer el área de recorte, luego aplicar la transformación, luego dibujar el contenido. Apple recomienda minimizar los cambios de CTM (Matriz de Transformación Actual) en el bucle de dibujo.
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()
}
Veamos un ejemplo completo de creación de un gráfico degradado usando CGContext. El gráfico incluye tres sectores de diferentes colores con rellenos degradados y etiquetas de texto. El código demuestra la combinación de saveGState, clip, degradados y renderizado de texto en un solo 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
}
}
}
En este ejemplo, cada sector del gráfico se dibuja en su propio bloque saveGState/restoreGState. Este enfoque garantiza que la configuración de color y trayecto de un sector no afecte a los demás. El método addArc crea un arco desde el ángulo inicial hasta el final, y closePath cierra el sector hacia el centro. El texto de la etiqueta se coloca en el ángulo medio del sector usando las funciones trigonométricas cos y sin para calcular la posición.
Para mejorar el rendimiento durante el redibujado frecuente, se recomienda almacenar en caché los cálculos de ángulos y posiciones en un array separado. CGContext ejecuta todas las operaciones en la CPU, por lo que las escenas complejas con decenas de sectores pueden requerir optimización — por ejemplo, renderizado previo en CGLayer o uso de Metal para aceleración GPU. Para la mayoría de las tareas de UI con 5–10 elementos, el rendimiento de CGContext sigue siendo aceptable.
Preguntas Frecuentes
Llame a UIGraphicsGetCurrentContext() dentro del método draw(_:) de UIView o dentro de un bloque UIGraphicsBeginImageContextWithOptions. Para capas CALayer, use el método draw(in:) de CALayerDelegate, que recibe un contexto listo.
fillPath rellena el interior del trayecto actual con el color de setFillColor. strokePath dibuja una línea a lo largo del trayecto con los parámetros de setStrokeColor, setLineWidth y setLineCap. Ambas operaciones se realizan secuencialmente: primero relleno, luego trazo si es necesario.
Bitmap CGContext es un contexto creado mediante CGBitmapContextCreate que dibuja en un búfer de memoria en lugar de la pantalla. Se usa para generación de imágenes en segundo plano, procesamiento de gráficos sin visualización y creación de texturas para Metal u OpenGL.
Core Graphics no proporciona un método para restablecer toda la configuración. Use saveGState antes de los cambios y restoreGState para volver al estado original. Alternativamente, cree un nuevo contexto con los mismos parámetros.
Antes de llamar a drawLinearGradient, establezca el área de recorte mediante clip en el trayecto deseado. Sin clip, el degradado llena todo el contexto. Orden: addPath → clip → drawLinearGradient — garantiza el degradado dentro de la forma.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también