CAAnimation è una classe base astratta di Core Animation che definisce l'interfaccia comune per tutti i tipi di animazioni: CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup, CATransition. L'articolo spiega la gerarchia delle classi, le proprietà chiave, il raggruppamento delle animazioni e gli esempi pratici in Swift.
Punti chiave
CAAnimation è una classe astratta di Core Animation che definisce l'interfaccia comune per tutte le animazioni. Implementa il protocollo CAMediaTiming (durata, ripetizione, inversione automatica) e CAMediaTimingFillMode (comportamento prima/dopo l'animazione). CAAnimation non può essere istanziata direttamente — utilizza una delle sue sottoclassi: CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup, CATransition o CAAnimation (tramite animationForKeyPath).
Ogni CAAnimation viene aggiunta a un CALayer tramite il metodo add(_:forKey:). Il parametro forKey è un identificatore univoco dell'animazione sul layer. Un keyPath può avere una sola animazione attiva. Per sostituire un'animazione, usa removeAnimation(forKey:) prima di aggiungerne una nuova.
Secondo Apple, CAAnimation è una modifica "temporanea" del layer. Al termine dell'animazione, il layer di presentazione torna ai valori del layer modello se fillMode e isRemovedOnCompletion non sono impostati.
Core Animation fornisce quattro sottoclassi principali di CAAnimation, ciascuna per il proprio scenario di animazione. Comprendere la gerarchia aiuta a scegliere il tipo giusto per l'attività.
| Classe | Scopo | Caratteristiche principali |
|---|---|---|
| CABasicAnimation | Anima una proprietà da A a B | fromValue, toValue, byValue, keyPath |
| CAKeyframeAnimation | Animazione su più fotogrammi chiave | values, keyTimes, path, calculationMode |
| CAAnimationGroup | Raggruppa più animazioni | array animations, duration singolo |
| CATransition | Transizione tra stati del layer | type (fade/push/moveIn/reveal), subtype, startProgress |
CABasicAnimation è la sottoclasse più semplice e popolare. CAKeyframeAnimation viene utilizzata per traiettorie complesse (ad esempio, movimento lungo una curva di Bezier). CAAnimationGroup esegue più animazioni in parallelo. CATransition è una transizione pronta all'uso tra immagini o stati di contenuto.
Il protocollo CAMediaTiming è una parte fondamentale di CAAnimation. Definisce le proprietà temporali di base: duration, repeatCount, repeatDuration, autoreverses, beginTime (tempo di inizio relativo al genitore), timeOffset (offset all'interno di un ciclo), speed (velocità di riproduzione).
La proprietà fillMode (CAMediaTimingFillMode) determina la visualizzazione del layer prima (backwards) e dopo (forwards) l'animazione. Valori: removed (predefinito — ritorna al layer modello), forwards (rimane nello stato finale), backwards (mostra lo stato iniziale prima dell'inizio), both (combina entrambi i comportamenti). fillMode funziona solo quando isRemovedOnCompletion = false.
CAAnimation eredita CAMediaTiming e può essere annidata in un'animazione genitore (CAAnimationGroup). In questo caso, beginTime viene calcolato rispetto all'inizio del genitore e duration è limitata dalla durata del genitore. Speed = 2.0 raddoppia la velocità dell'animazione.
CAAnimationGroup combina più istanze di CAAnimation in un unico gruppo. Tutte le animazioni figlie partono in parallelo a meno che beginTime non sia impostato per ciascuna. Il gruppo ha una propria duration, che limita la durata massima delle animazioni figlie. La timingFunction del gruppo viene utilizzata come valore predefinito se un'animazione figlia non imposta la propria.
CAKeyframeAnimation anima una proprietà attraverso più fotogrammi chiave, definiti da un array di values. Il parametro keyTimes (array di NSNumber da 0 a 1) definisce i marcatori temporali per ciascun fotogramma. calculationMode specifica l'interpolazione: linear, discrete (nessuna interpolazione), paced (velocità uniforme), cubic (spline), cubicPaced.
import QuartzCore
// CAAnimationGroup — combinazione di animazioni
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 — movimento su traiettoria
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 valori personalizzati
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 alla posizione corrente
layer.add(bounce, forKey: nil)
}CAAnimationGroup esegue fade, scale e rotate in parallelo con una durata di 2.0. CAKeyframeAnimation con path e calculationMode = .cubicPaced fornisce un movimento uniforme lungo una curva di Bezier con rotazione automatica (rotationMode = .auto). bounceAnimation utilizza isAdditive per l'offset relativo.
Un esempio completo di CAAnimation per animazioni complesse del layer utilizzando CATransition per il cambio di contenuto e CAAnimationGroup per effetti di pulsazione.
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 — transizione tra stati
let transition = CATransition()
transition.type = .fade
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
demoLayer.add(transition, forKey: nil)
// Cambiare contenuto tramite transazione
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 transizione fluida tra due stati di backgroundColor. CAAnimationGroup combina scale, opacity e shadowOpacity per un effetto di pulsazione. removeAllAnimations() cancella tutte le animazioni e riporta il layer ai valori originali del layer modello.
Domande frequenti
CABasicAnimation anima una proprietà da un valore iniziale (fromValue) a un valore finale (toValue) con interpolazione uniforme. CAKeyframeAnimation permette di specificare un array di valori intermedi (values) e marcatori temporali (keyTimes) per un'animazione non lineare per fotogrammi chiave, inclusi movimenti basati su curve tramite path.
CAAnimationGroup è necessario quando più animazioni devono essere eseguite in parallelo con sincronizzazione garantita: la durata del gruppo limita tutte le animazioni figlie. Utilizza group per effetti combinati: scala + modifica dell'opacità + rotazione simultaneamente.
fillMode determina la visualizzazione del layer prima (backwards) e dopo (forwards) l'animazione. Il valore .forwards mantiene il layer nello stato finale dopo il completamento dell'animazione (richiede isRemovedOnCompletion = false). .both combina backwards (stato iniziale prima dell'inizio) e forwards.
CAAnimation è un oggetto di animazione (istruzione) che viene aggiunto a un CALayer tramite layer.add(animation, forKey:). L'animazione esiste come oggetto separato, può essere riutilizzata (con copia) e viene gestita tramite CAMediaTiming. Un layer può avere più animazioni con chiavi diverse.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche