Core Animation: conceptos básicos, CALayer y animación en iOS

Autor: IT Sectr Publicado: 2026-03-01 Tiempo de lectura: 8 min

Core Animation es el framework de animación de bajo nivel de Apple que opera a nivel de CALayer y renderiza contenido en la GPU. Core Animation es la base de todas las animaciones en iOS y macOS: UIKit, AppKit, SceneKit y SpriteKit están construidos sobre él. Este artículo explica la arquitectura de CALayer, CABasicAnimation, CATransaction y técnicas prácticas.

Puntos clave

  • CALayer — la clase base de Core Animation para gestionar la visualización de contenido en la GPU
  • CABasicAnimation — una animación simple de una propiedad de CALayer desde fromValue hasta toValue
  • CATransaction — agrupación de animaciones en una sola transacción con duración y finalización compartidas
  • CAAnimation — una clase base abstracta de la que heredan CABasicAnimation, CAKeyframeAnimation y CAAnimationGroup
  • Render server — un proceso separado (backboardd) que interpola los fotogramas de animación en la GPU

¿Qué es Core Animation?

Core Animation es el framework gráfico de Apple introducido en Mac OS X 10.5 Leopard (2007) y portado a iOS con la primera versión de iPhone OS (2007). Core Animation gestiona la composición, animación y renderizado de capas (CALayer) en la GPU. Cada UIView en iOS tiene un CALayer incorporado (view.layer) a través del cual ocurre todo el dibujo.

Core Animation opera bajo el principio de animación implícita: algunos cambios de propiedades de CALayer se animan automáticamente (CABasicAnimation para position, bounds, opacity, backgroundColor). Las animaciones implícitas usan CATransaction por defecto con una duración de 0.25 segundos y una curva easeInOut.

Según Apple WWDC 2024, Core Animation procesa hasta 120 FPS en dispositivos ProMotion, utilizando Metal para el renderizado en GPU. El consumo de memoria de una capa típica es de 4 bytes por píxel (RGBA) + ~100 bytes de overhead por capa. Se recomienda no superar las 1000 capas en pantalla para mantener 60 FPS estables.

Arquitectura de CALayer

CALayer es la base de Core Animation. Cada CALayer contiene contenido de mapa de bits (o una referencia a textura de GPU) y define la geometría (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). Las capas no manejan eventos táctiles — UIView/UIScrollView se encargan de eso. Las capas forman una jerarquía (layer tree) que refleja la jerarquía de vistas.

Core Animation mantiene tres árboles de capas: el model layer tree (propiedades reales), el presentation layer tree (visualización actual durante la animación) y el render tree (datos para GPU). La capa de presentación se utiliza para leer valores intermedios de animación en tiempo real.

Tipos de CALayer

CALayer tiene subclases especializadas: CAShapeLayer (gráficos vectoriales), CAGradientLayer (gradiente), CATextLayer (texto), CATiledLayer (imágenes grandes divididas en mosaicos), CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer es el más popular para animación personalizada gracias al soporte de CGPath y la animación de strokeStart/strokeEnd.

CABasicAnimation — animación básica de propiedades

CABasicAnimation es una subclase de CAAnimation que anima una única propiedad de CALayer desde un valor inicial (fromValue) hasta un valor final (toValue) o mediante un cambio relativo (byValue). La animación se añade a la capa mediante layer.add(animation, forKey:) y se ejecuta en el render server sin participación de la aplicación en cada fotograma.

La clave (keyPath) es una cadena que especifica la propiedad: opacity, position, bounds, transform.rotation.z, cornerRadius, shadowOpacity, etc. Core Animation admite más de 60 keyPaths animables. Para propiedades personalizadas se utilizan CATransaction y la capa de presentación.

swift
import QuartzCore

// CABasicAnimation para opacity y cornerRadius
func animateLayer() {
    let layer = CALayer()
    layer.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
    layer.backgroundColor = UIColor.systemBlue.cgColor
    view.layer.addSublayer(layer)

    // 1. Animación de opacidad
    let fadeAnim = CABasicAnimation(keyPath: "opacity")
    fadeAnim.fromValue = 1.0
    fadeAnim.toValue = 0.2
    fadeAnim.duration = 2.0
    fadeAnim.autoreverses = true
    fadeAnim.repeatCount = .infinity

    // 2. Animación de radio de esquina
    let cornerAnim = CABasicAnimation(keyPath: "cornerRadius")
    cornerAnim.fromValue = 0
    cornerAnim.toValue = 50
    cornerAnim.duration = 2.0
    cornerAnim.autoreverses = true
    cornerAnim.repeatCount = .infinity

    layer.add(fadeAnim, forKey: "fade")
    layer.add(cornerAnim, forKey: "corner")
}

// Animación de position con ease-in-out
func moveLayer(_ layer: CALayer, to point: CGPoint) {
    let anim = CABasicAnimation(keyPath: "position")
    anim.fromValue = NSValue(cgPoint: layer.position)
    anim.toValue = NSValue(cgPoint: point)
    anim.duration = 0.6
    anim.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
    anim.isRemovedOnCompletion = false
    anim.fillMode = .forwards
    layer.add(anim, forKey: "move")
    layer.position = point // actualizando model layer
}

Importante: CABasicAnimation es una visualización temporal (presentation layer). Después de que la animación se completa, la capa vuelve a sus valores del model layer. Para fijar el estado final, establezca isRemovedOnCompletion = false, fillMode = .forwards y actualice el model layer a los valores finales.

CATransaction — agrupación de animaciones

CATransaction es un mecanismo para agrupar animaciones de Core Animation en una sola transacción. CATransaction.begin() y CATransaction.commit() definen los límites de la transacción. Dentro de una transacción se pueden establecer parámetros compartidos: duration, timingFunction, completionBlock, disableActions. CATransaction es la base de las animaciones implícitas de CALayer.

La animación implícita ocurre cuando una propiedad de CALayer cambia fuera de un bloque de animación: layer.opacity = 0.5. Core Animation crea automáticamente una CABasicAnimation con la duración del CATransaction actual (por defecto 0.25 s). Para deshabilitar la animación implícita, use CATransaction.setDisableActions(true).

swift
// CATransaction — agrupación y finalización
func groupedAnimation() {
    CATransaction.begin()
    CATransaction.setAnimationDuration(1.5)
    CATransaction.setAnimationTimingFunction(
        CAMediaTimingFunction(name: .easeOut)
    )
    CATransaction.setCompletionBlock {
        print("All animations completed")
    }

    // Todos los cambios dentro de la transacción se animan con duración 1.5
    layer1.opacity = 0.3
    layer2.position = CGPoint(x: 200, y: 300)
    layer3.backgroundColor = UIColor.systemRed.cgColor

    CATransaction.commit()
}

// Deshabilitando animación implícita
func updateWithoutAnimation() {
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    layer.frame = newFrame // sin animación
    CATransaction.commit()
}

// Animando propiedades de CAShapeLayer
func animateProgress(percentage: CGFloat) {
    CATransaction.begin()
    CATransaction.setAnimationDuration(0.8)
    CATransaction.setCompletionBlock {
        print("Progress updated to (percentage)%")
    }
    progressLayer.strokeEnd = percentage / 100.0
    CATransaction.commit()
}

Ejemplos de código en Swift

Core Animation se integra con UIKit a través de la capa UIView. El ejemplo siguiente demuestra la animación de CAShapeLayer — un progreso circular con animación de longitud de arco y rotación de capa mediante CABasicAnimation.

swift
import UIKit
import QuartzCore

class CircularProgressView: UIView {

    private let progressLayer = CAShapeLayer()

    override func layoutSubviews() {
        super.layoutSubviews()

        let path = UIBezierPath(
            arcCenter: CGPoint(x: bounds.midX, y: bounds.midY),
            radius: bounds.width / 2 - 10,
            startAngle: -.pi / 2,
            endAngle: 3 * .pi / 2,
            clockwise: true
        )

        progressLayer.path = path.cgPath
        progressLayer.strokeColor = UIColor.systemBlue.cgColor
        progressLayer.lineWidth = 8
        progressLayer.fillColor = nil
        progressLayer.strokeEnd = 0
        progressLayer.lineCap = .round
        layer.addSublayer(progressLayer)
    }

    func setProgress(_ value: CGFloat, animated: Bool = true) {
        if animated {
            CATransaction.begin()
            CATransaction.setAnimationDuration(0.6)
            CATransaction.setAnimationTimingFunction(
                CAMediaTimingFunction(name: .easeOut)
            )
            progressLayer.strokeEnd = min(max(value, 0), 1)
            CATransaction.commit()
        } else {
            progressLayer.strokeEnd = value
        }
    }
}

CAShapeLayer anima la propiedad strokeEnd de 0 a 1, creando un efecto de “llenado” de progreso circular. CATransaction con duración 0.6 y easeOut hace que la animación sea suave. layer.lineCap = .round agrega extremos redondeados a la línea para un aspecto más limpio.

Preguntas frecuentes

¿Cuál es la diferencia entre Core Animation y UIView.animate?

Core Animation funciona a nivel de CALayer y se controla mediante CABasicAnimation y CATransaction. UIView.animate es un envoltorio de alto nivel sobre Core Animation que crea automáticamente CABasicAnimation para las propiedades de UIView. Core Animation ofrece más control: keyPath, timingFunction, fillMode, agrupación mediante CATransaction.

¿Qué es la animación implícita en Core Animation?

La animación implícita es una animación automática que ocurre cuando se cambia una propiedad animable de CALayer fuera de un bloque de animación. Por ejemplo, layer.opacity = 0.5 crea una CABasicAnimation con duración de 0.25 s. Las animaciones implícitas se gestionan mediante CATransaction y se pueden deshabilitar usando setDisableActions(true).

¿Cómo animar una propiedad personalizada de CALayer?

Para propiedades personalizadas, implemente action(forKey:) en CALayer y devuelva una CAAnimation. Alternativamente, use CALayer.display() para dibujo manual con animación mediante CADisplayLink. Para propiedades que admiten CABasicAnimation, simplemente especifique el keyPath como una cadena.

¿Por qué CALayer es más eficiente que UIView para animación?

CALayer es más ligero que UIView: no tiene manejadores de eventos (touches, gestures), no participa en Auto Layout y no soporta accesibilidad. Un CALayer típico ocupa ~100 bytes frente a ~300+ de UIView. Core Animation procesa las capas en el render server en la GPU sin bloquear el hilo principal.

Resumen

  • Core Animation — framework de bajo nivel de Apple para animación de CALayer con renderizado en GPU
  • CALayer — clase base con más de 60 propiedades animables, compatible con CAShapeLayer, CAGradientLayer, CATextLayer
  • CABasicAnimation — animación de una sola propiedad con fromValue/toValue, se añade mediante layer.add(animation, forKey:)
  • CATransaction — agrupación de animaciones con duración, timingFunction y completionBlock compartidos
  • Animación implícita — animación automática al cambiar propiedades de CALayer (duración 0.25 s)
  • Presentation layer — estado actual de la capa durante la animación, se usa para leer valores intermedios
  • Rendimiento — hasta 120 FPS en ProMotion, hasta 1000 capas a 60 FPS, 4 bytes/píxel

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.

Discutir el proyecto

Lea también