CAShapeLayer es una subclase de CALayer diseñada para el renderizado acelerado por hardware de trazados vectoriales en la GPU. A diferencia de CALayer básico, que trabaja con imágenes rasterizadas a través de contents, CAShapeLayer renderiza formas arbitrarias definidas mediante CGPath sin crear un buffer fuera de pantalla separado. Según Apple QuartzCore Documentation, 2025, CAShapeLayer utiliza aceleración hardware para el suavizado de bordes y admite animación de path, strokeStart y strokeEnd. Es una herramienta estándar para crear iconos, indicadores de progreso y máscaras en iOS.
Puntos Clave
CAShapeLayer es una capa especializada para renderizar gráficos vectoriales, introducida en iOS 3.0. A diferencia de CALayer, que almacena una imagen rasterizada, CAShapeLayer almacena una descripción matemática de un trazado — CGPath — y lo renderiza directamente en la GPU. Esto permite escalar la forma sin pérdida de calidad y animar sus propiedades sin redescribir el contenido.
Arquitectónicamente, CAShapeLayer hereda todas las capacidades de CALayer: sombras, bordes, transformaciones, máscaras. Pero añade propiedades específicas para trabajar con trazados: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, miterLimit, strokeStart, strokeEnd y fillRule. Cada una de estas propiedades puede ser animada a través de CABasicAnimation.
Según Apple Documentation, CAShapeLayer utiliza aceleración hardware para el renderizado. A diferencia del dibujo mediante Core Graphics en drawRect:, donde la CPU renderiza el trazado en un contexto rasterizado, CAShapeLayer envía comandos directamente a la GPU a través de Metal. El resultado es un mayor rendimiento, especialmente durante la animación.
CAShapeLayer es particularmente útil para elementos de interfaz que cambian de forma en respuesta a acciones del usuario: indicadores de progreso, gráficos, iconos de barra de pestañas, máscaras para animaciones de revelación de contenido.
El proceso de renderizado de CAShapeLayer difiere del CALayer básico. En lugar de almacenar un buffer rasterizado con píxeles, CAShapeLayer pasa una descripción de vértices del trazado a la GPU — un conjunto de puntos, curvas Bezier y segmentos de línea. La GPU rasteriza este trazado en una sola pasada, aplicando colores de relleno y trazo en la etapa del shader de fragmentos.
Este enfoque ofrece dos ventajas: escalado sin pérdida de calidad (los gráficos vectoriales permanecen nítidos en cualquier resolución) y animación eficiente — cuando el trazado cambia, la GPU recalcula solo los píxeles modificados, no toda la pantalla.
path — la propiedad central de CAShapeLayer, que acepta un CGPath. El trazado puede contener líneas, arcos, curvas Bezier y rectángulos. Se crea mediante UIBezierPath en Swift o CGPath en Core Graphics. Ejemplo: UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath crea un rectángulo redondeado.
La propiedad lineDashPattern permite crear líneas discontinuas. Acepta un array de números: [6, 3] significa 6 puntos de trazo y 3 puntos de espacio. lineDashPhase establece el desplazamiento del patrón y se puede animar para un efecto de línea discontinua en movimiento.
La elección entre CAShapeLayer y CALayer básico depende del tipo de contenido. Si el elemento es un área rectangular con fondo, borde y sombra — CALayer es suficiente. Si el elemento tiene una forma arbitraria, requiere animación del trazado o escalado sin pérdida de calidad — CAShapeLayer es preferible.
El rendimiento también difiere. CALayer con cornerRadius y masksToBounds crea un buffer fuera de pantalla para recortar contenido, añadiendo 2–5 ms por fotograma. CAShapeLayer no requiere buffer fuera de pantalla — el recorte se realiza a nivel del shader de vértices. Para elementos con máscaras complejas, CAShapeLayer puede ser 2–3 veces más rápido.
Combinar CAShapeLayer con otras capas es un patrón común. Por ejemplo, CAGradientLayer usa CAShapeLayer como máscara para crear una forma con relleno degradado. Este enfoque proporciona tanto calidad vectorial como relleno degradado sin pérdida de rendimiento.
La animación de path es una de las características más potentes de CAShapeLayer. Si ambos trazados (inicial y final) tienen el mismo número de puntos de control y segmentos, Core Animation realiza una interpolación suave entre ellos. El resultado es un efecto de transformación de una forma a otra.
Condición de compatibilidad del trazado: el UIBezierPath inicial y final deben tener la misma estructura — el número de llamadas a moveTo, addLine, addCurve y addQuadCurve debe coincidir. Si la estructura difiere, la animación será instantánea, sin interpolación.
Según Apple WWDC 2024, la combinación de strokeStart y strokeEnd es el patrón de animación de CAShapeLayer más utilizado. Animar strokeEnd de 0.0 a 1.0 crea un efecto de dibujo del trazado de principio a fin. Esto se utiliza en indicadores de carga, animaciones de revelación de gráficos y transiciones personalizadas entre pantallas.
Para crear un efecto pulsante, anime strokeEnd y opacity simultáneamente con diferentes funciones de temporización. Para un efecto de hormigas marchantes, anime lineDashPhase con un lineDashPattern fijo. Ambas técnicas se implementan mediante CABasicAnimation sin participación de la CPU.
CAShapeLayer se usa a menudo como máscara para otras capas. Por ejemplo, para animación de revelación de contenido: inicialmente, mask.path es un rectángulo de tamaño cero, y el final es de tamaño completo. Core Animation interpola el trazado y el contenido se revela suavemente.
Este patrón se utiliza en iOS para la animación de expansión de tarjetas, presentación de ventanas modales y transiciones entre controladores de vista. A diferencia de la animación de alpha, la animación de máscara de CAShapeLayer proporciona un efecto de revelado más natural con formas arbitrarias.
El primer ejemplo — creación de un indicador de progreso circular con animación de strokeEnd. Este es un elemento de interfaz estándar que demuestra las capacidades principales de CAShapeLayer:
func createProgressIndicator(in view: UIView) -> CAShapeLayer {
let circlePath = UIBezierPath(
arcCenter: CGPoint(x: 50, y: 50),
radius: 40,
startAngle: -.pi / 2,
endAngle: 3 * .pi / 2,
clockwise: true
)
let trackLayer = CAShapeLayer()
trackLayer.path = circlePath.cgPath
trackLayer.strokeColor = UIColor.systemGray5.cgColor
trackLayer.fillColor = nil
trackLayer.lineWidth = 8
view.layer.addSublayer(trackLayer)
let progressLayer = CAShapeLayer()
progressLayer.path = circlePath.cgPath
progressLayer.strokeColor = UIColor.systemBlue.cgColor
progressLayer.fillColor = nil
progressLayer.lineWidth = 8
progressLayer.lineCap = .round
progressLayer.strokeEnd = 0
view.layer.addSublayer(progressLayer)
return progressLayer
}
// Animate to 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)
El segundo ejemplo — animación de transformación entre un círculo y un cuadrado. Ambos UIBezierPath tienen una estructura compatible:
let morphLayer = CAShapeLayer()
morphLayer.fillColor = UIColor.systemPurple.cgColor
morphLayer.frame = rect
let circlePath = UIBezierPath(roundedRect: rect, cornerRadius: rect.width / 2)
let squarePath = UIBezierPath(roundedRect: rect, cornerRadius: 0)
morphLayer.path = circlePath.cgPath
let morphAnimation = CABasicAnimation(keyPath: "path")
morphAnimation.toValue = squarePath.cgPath
morphAnimation.duration = 0.6
morphAnimation.autoreverses = true
morphAnimation.repeatCount = .infinity
morphLayer.add(morphAnimation, forKey: "morph")
El tercer ejemplo — una máscara CAShapeLayer para animación de revelación de contenido. La máscara se expande desde el centro hacia los bordes:
func revealContent(_ view: UIView) {
let maskLayer = CAShapeLayer()
let size = view.bounds.size.width * 1.5
let center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
let initialPath = UIBezierPath(arcCenter: center, radius: 0, startAngle: 0, endAngle: .pi * 2, clockwise: true)
let finalPath = UIBezierPath(arcCenter: center, radius: size, startAngle: 0, endAngle: .pi * 2, clockwise: true)
maskLayer.path = initialPath.cgPath
view.layer.mask = maskLayer
let animation = CABasicAnimation(keyPath: "path")
animation.toValue = finalPath.cgPath
animation.duration = 0.4
animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
maskLayer.add(animation, forKey: "reveal")
maskLayer.path = finalPath.cgPath
}
Preguntas Frecuentes
drawRect usa la CPU para renderizar en un contexto rasterizado — esto es lento para animaciones. CAShapeLayer renderiza el trazado en la GPU, ofreciendo 60 FPS durante animaciones de path, strokeEnd y transformaciones. Además, CAShapeLayer no requiere redibujado al cambiar de tamaño — la forma se escala vectorialmente.
La animación suave del trazado requiere estructura idéntica del UIBezierPath inicial y final. El número de llamadas a moveTo, addLine, addCurve debe coincidir. Use UIBezierPath con el mismo número de segmentos para las formas inicial y final.
Establezca lineDashPattern — un array de números que alternan longitudes de trazo y espacio. Por ejemplo, [8, 4] crea trazos de 8pt con espacios de 4pt. Para un efecto de hormigas marchantes, anime lineDashPhase mediante CABasicAnimation con una función de temporización lineal.
Sí, este es uno de los casos de uso principales. Asigne CAShapeLayer a la propiedad mask de cualquier CALayer, incluyendo CAGradientLayer y otras subclases. Animar el trazado de la máscara crea un efecto de revelado suave del contenido a través de una forma arbitraria.
Cree un CAGradientLayer y establezca su mask = CAShapeLayer con el trazado deseado. El degradado será visible solo dentro del trazado de la máscara. Este patrón combina las ventajas de forma vectorial de CAShapeLayer y el relleno degradado de CAGradientLayer.
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