CAAnimation es una clase base abstracta de Core Animation que define la interfaz común para todos los tipos de animaciones: CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup, CATransition. Este artículo explica la jerarquía de clases, las propiedades clave, la agrupación de animaciones y ejemplos prácticos en Swift.
Conclusiones clave
CAAnimation es una clase abstracta de Core Animation que define la interfaz común para todas las animaciones. Implementa el protocolo CAMediaTiming (duración, repetición, autoreverso) y CAMediaTimingFillMode (comportamiento antes/después de la animación). CAAnimation no se puede instanciar directamente — use una de sus subclases: CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup, CATransition o CAAnimation (a través de animationForKeyPath).
Cada CAAnimation se añade a un CALayer mediante el método add(_:forKey:). El parámetro forKey es un identificador único de animación en la capa. Un mismo keyPath solo puede tener una animación activa. Para reemplazar una animación, use removeAnimation(forKey:) antes de añadir una nueva.
Según Apple, CAAnimation es un cambio "temporal" de la capa. Una vez completada la animación, la capa de presentación vuelve a los valores de la capa modelo si no se han establecido fillMode e isRemovedOnCompletion.
Core Animation proporciona cuatro subclases principales de CAAnimation, cada una para su propio escenario de animación. Comprender la jerarquía ayuda a elegir el tipo adecuado para cada tarea.
| Clase | Propósito | Características clave |
|---|---|---|
| CABasicAnimation | Anima una propiedad de A a B | fromValue, toValue, byValue, keyPath |
| CAKeyframeAnimation | Animación por múltiples fotogramas clave | values, keyTimes, path, calculationMode |
| CAAnimationGroup | Agrupa múltiples animaciones | animations array, duration único |
| CATransition | Transición entre estados de capa | type (fade/push/moveIn/reveal), subtype, startProgress |
CABasicAnimation es la subclase más simple y popular. CAKeyframeAnimation se usa para trayectorias complejas (por ejemplo, movimiento a lo largo de una curva Bezier). CAAnimationGroup ejecuta múltiples animaciones en paralelo. CATransition es una transición predefinida entre imágenes o estados de contenido.
El protocolo CAMediaTiming es una parte fundamental de CAAnimation. Define las propiedades temporales básicas: duration, repeatCount, repeatDuration, autoreverses, beginTime (tiempo de inicio relativo al padre), timeOffset (desplazamiento dentro de un ciclo), speed (velocidad de reproducción).
La propiedad fillMode (CAMediaTimingFillMode) determina la visualización de la capa antes (backwards) y después (forwards) de la animación. Valores: removed (predeterminado — vuelve a la capa modelo), forwards (permanece en el estado final), backwards (muestra el estado inicial antes del inicio), both (combina ambos comportamientos). fillMode funciona solo cuando isRemovedOnCompletion = false.
CAAnimation hereda CAMediaTiming y puede anidarse en una animación padre (CAAnimationGroup). En este caso, beginTime se calcula respecto al inicio del padre, y duration está limitada por la duración del padre. Speed = 2.0 duplica la velocidad de la animación.
CAAnimationGroup combina múltiples instancias de CAAnimation en un solo grupo. Todas las animaciones hijas se inician en paralelo a menos que se establezca beginTime para cada una. El grupo tiene su propio duration, que limita la duración máxima de las animaciones hijas. El timingFunction del grupo se usa como valor predeterminado si una animación hija no establece el suyo propio.
CAKeyframeAnimation anima una propiedad a través de múltiples fotogramas clave, definidos por un array de values. El parámetro keyTimes (array de NSNumber de 0 a 1) define las marcas de tiempo para cada fotograma. calculationMode especifica la interpolación: linear, discrete (sin interpolación), paced (velocidad uniforme), cubic (spline), cubicPaced.
import QuartzCore
// CAAnimationGroup — combinación de animaciones
func complexLayerAnimation(_ layer: CALayer) {
let fade = CABasicAnimation(keyPath: "opacity")
fade.fromValue = 1.0
fade.toValue = 0.3
let scale = CABasicAnimation(keyPath: "transform.scale")
scale.fromValue = 1.0
scale.toValue = 1.5
let rotate = CABasicAnimation(keyPath: "transform.rotation.z")
rotate.fromValue = 0
rotate.toValue = Double.pi * 2
let group = CAAnimationGroup()
group.animations = [fade, scale, rotate]
group.duration = 2.0
group.repeatCount = .infinity
group.autoreverses = true
layer.add(group, forKey: "pulse")
}
// CAKeyframeAnimation — movimiento por trayectoria
func animateAlongPath(_ layer: CALayer) {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addCurve(
to: CGPoint(x: 200, y: 300),
controlPoint1: CGPoint(x: 100, y: 0),
controlPoint2: CGPoint(x: 100, y: 300)
)
let anim = CAKeyframeAnimation(keyPath: "position")
anim.path = path.cgPath
anim.duration = 1.5
anim.calculationMode = .cubicPaced
anim.rotationMode = .auto
anim.fillMode = .forwards
anim.isRemovedOnCompletion = false
layer.add(anim, forKey: "pathAnim")
layer.position = CGPoint(x: 200, y: 300)
}
// CAKeyframeAnimation con valores personalizados
func bounceAnimation(_ layer: CALayer) {
let bounce = CAKeyframeAnimation(keyPath: "position.y")
bounce.values = [0, -50, 0, -25, 0, -10, 0]
bounce.keyTimes = [0, 0.15, 0.3, 0.45, 0.6, 0.8, 1.0]
bounce.duration = 0.8
bounce.timingFunction = CAMediaTimingFunction(name: .easeOut)
bounce.isAdditive = true // relativo a la posición actual
layer.add(bounce, forKey: nil)
}CAAnimationGroup ejecuta fade, scale y rotate en paralelo con una duración de 2.0. CAKeyframeAnimation con path y calculationMode = .cubicPaced proporciona un movimiento uniforme a lo largo de una curva Bezier con rotación automática (rotationMode = .auto). bounceAnimation usa isAdditive para el desplazamiento relativo.
Un ejemplo completo de CAAnimation para animación compleja de capas usando CATransition para el cambio de contenido y CAAnimationGroup para efectos de pulso.
import UIKit
import QuartzCore
class AnimationDemoView: UIView {
private let demoLayer = CALayer()
private var currentColor: CGColor = UIColor.systemBlue.cgColor
override func layoutSubviews() {
super.layoutSubviews()
demoLayer.frame = CGRect(x: bounds.midX - 40, y: bounds.midY - 40,
width: 80, height: 80)
demoLayer.backgroundColor = currentColor
demoLayer.cornerRadius = 12
layer.addSublayer(demoLayer)
}
func animateTransition() {
// CATransition — transición entre estados
let transition = CATransition()
transition.type = .fade
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
demoLayer.add(transition, forKey: nil)
// Cambiando contenido mediante transacción
currentColor = currentColor == UIColor.systemBlue.cgColor
? UIColor.systemRed.cgColor
: UIColor.systemBlue.cgColor
demoLayer.backgroundColor = currentColor
}
func startPulse() {
let scaleUp = CABasicAnimation(keyPath: "transform.scale")
scaleUp.fromValue = 1.0
scaleUp.toValue = 1.3
let fadeOut = CABasicAnimation(keyPath: "opacity")
fadeOut.fromValue = 1.0
fadeOut.toValue = 0.6
let glow = CABasicAnimation(keyPath: "shadowOpacity")
glow.fromValue = 0.0
glow.toValue = 0.8
let group = CAAnimationGroup()
group.animations = [scaleUp, fadeOut, glow]
group.duration = 1.2
group.autoreverses = true
group.repeatCount = .infinity
group.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
demoLayer.add(group, forKey: "pulse")
}
func stopAnimations() {
demoLayer.removeAllAnimations()
demoLayer.transform = CATransform3DIdentity
demoLayer.opacity = 1.0
demoLayer.shadowOpacity = 0.0
}
}CATransition con type: .fade crea una transición suave entre dos estados de backgroundColor. CAAnimationGroup combina scale, opacity y shadowOpacity para un efecto de pulso. removeAllAnimations() cancela todas las animaciones y devuelve la capa a sus valores originales de la capa modelo.
Preguntas frecuentes
CABasicAnimation anima una propiedad desde un valor inicial (fromValue) hasta un valor final (toValue) con interpolación uniforme. CAKeyframeAnimation permite especificar un array de valores intermedios (values) y marcas de tiempo (keyTimes) para una animación no lineal por fotogramas clave, incluyendo movimiento basado en curvas mediante path.
CAAnimationGroup es necesario cuando múltiples animaciones deben ejecutarse en paralelo con sincronización garantizada: la duración del grupo limita todas las animaciones hijas. Use group para efectos combinados: escalado + cambio de opacidad + rotación simultáneamente.
fillMode determina la visualización de la capa antes (backwards) y después (forwards) de la animación. El valor .forwards mantiene la capa en el estado final después de completar la animación (requiere isRemovedOnCompletion = false). .both combina backwards (estado inicial antes del inicio) y forwards.
CAAnimation es un objeto de animación (instrucción) que se añade a un CALayer mediante layer.add(animation, forKey:). La animación existe como un objeto separado, puede reutilizarse (con copia) y se gestiona a través de CAMediaTiming. Una capa puede tener múltiples animaciones con diferentes claves.
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