Core Animation: basi, CALayer e animazione in iOS

Autore: IT Sectr Pubblicato: 2026-03-01 Tempo di lettura: 8 min

Core Animation è il framework di animazione di basso livello di Apple che opera a livello di CALayer e renderizza il contenuto sulla GPU. Core Animation è la base di tutte le animazioni in iOS e macOS: UIKit, AppKit, SceneKit e SpriteKit sono costruiti su di esso. Questo articolo spiega l’architettura di CALayer, CABasicAnimation, CATransaction e le tecniche pratiche.

Punti chiave

  • CALayer — la classe base di Core Animation per gestire la visualizzazione dei contenuti sulla GPU
  • CABasicAnimation — un’animazione semplice di una proprietà di CALayer da fromValue a toValue
  • CATransaction — raggruppamento di animazioni in una singola transazione con durata e completamento condivisi
  • CAAnimation — una classe base astratta da cui ereditano CABasicAnimation, CAKeyframeAnimation e CAAnimationGroup
  • Render server — un processo separato (backboardd) che interpola i fotogrammi dell’animazione sulla GPU

Cos’è Core Animation?

Core Animation è il framework grafico di Apple introdotto in Mac OS X 10.5 Leopard (2007) e portato su iOS con la prima versione di iPhone OS (2007). Core Animation gestisce la composizione, l’animazione e il rendering dei layer (CALayer) sulla GPU. Ogni UIView in iOS ha un CALayer integrato (view.layer) attraverso il quale avviene tutto il disegno.

Core Animation opera secondo il principio dell’animazione implicita: alcune modifiche delle proprietà di CALayer si animano automaticamente (CABasicAnimation per position, bounds, opacity, backgroundColor). Le animazioni implicite utilizzano CATransaction per impostazione predefinita con una durata di 0,25 secondi e una curva easeInOut.

Secondo Apple WWDC 2024, Core Animation elabora fino a 120 FPS sui dispositivi ProMotion, utilizzando Metal per il rendering GPU. L’impronta di memoria di un layer tipico è di 4 byte per pixel (RGBA) + ~100 byte di overhead per layer. Si consiglia di non superare i 1000 layer sullo schermo per 60 FPS stabili.

Architettura di CALayer

CALayer è il fondamento di Core Animation. Ogni CALayer contiene contenuto bitmap (o un riferimento a texture GPU) e definisce la geometria (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). I layer non gestiscono gli eventi tattili — UIView/UIScrollView se ne occupano. I layer formano una gerarchia (layer tree) che rispecchia la gerarchia delle viste.

Core Animation mantiene tre alberi di layer: il model layer tree (proprietà effettive), il presentation layer tree (visualizzazione corrente durante l’animazione) e il render tree (dati GPU). Il presentation layer viene utilizzato per leggere i valori intermedi dell’animazione in tempo reale.

Tipi di CALayer

CALayer ha sottoclassi specializzate: CAShapeLayer (grafica vettoriale), CAGradientLayer (gradiente), CATextLayer (testo), CATiledLayer (immagini grandi divise in tile), CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer è il più popolare per l’animazione personalizzata grazie al supporto di CGPath e all’animazione strokeStart/strokeEnd.

CABasicAnimation — animazione di base delle proprietà

CABasicAnimation è una sottoclasse di CAAnimation che anima una singola proprietà di CALayer da un valore iniziale (fromValue) a un valore finale (toValue) o mediante una modifica relativa (byValue). L’animazione viene aggiunta al layer tramite layer.add(animation, forKey:) e viene eseguita nel render server senza il coinvolgimento dell’app su ogni fotogramma.

La chiave (keyPath) è una stringa che specifica la proprietà: opacity, position, bounds, transform.rotation.z, cornerRadius, shadowOpacity, ecc. Core Animation supporta oltre 60 keyPath animabili. Per le proprietà personalizzate vengono utilizzati CATransaction e il presentation layer.

swift
import QuartzCore

// CABasicAnimation per opacity e 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. Animazione dell’opacità
    let fadeAnim = CABasicAnimation(keyPath: "opacity")
    fadeAnim.fromValue = 1.0
    fadeAnim.toValue = 0.2
    fadeAnim.duration = 2.0
    fadeAnim.autoreverses = true
    fadeAnim.repeatCount = .infinity

    // 2. Animazione del raggio d’angolo
    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")
}

// Animazione di 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 // aggiornamento del model layer
}

Importante: CABasicAnimation è una visualizzazione temporanea (presentation layer). Al termine dell’animazione, il layer torna ai suoi valori del model layer. Per congelare lo stato finale, impostare isRemovedOnCompletion = false, fillMode = .forwards e aggiornare il model layer ai valori finali.

CATransaction — raggruppamento di animazioni

CATransaction è un meccanismo per raggruppare le animazioni di Core Animation in un’unica transazione. CATransaction.begin() e CATransaction.commit() definiscono i confini della transazione. All’interno di una transazione è possibile impostare parametri condivisi: duration, timingFunction, completionBlock, disableActions. CATransaction è il fondamento delle animazioni implicite di CALayer.

L’animazione implicita si verifica quando una proprietà di CALayer viene modificata al di fuori di un blocco di animazione: layer.opacity = 0,5. Core Animation crea automaticamente una CABasicAnimation con la durata della CATransaction corrente (default 0,25 s). Per disabilitare l’animazione implicita, utilizzare CATransaction.setDisableActions(true).

swift
// CATransaction — raggruppamento e completamento
func groupedAnimation() {
    CATransaction.begin()
    CATransaction.setAnimationDuration(1.5)
    CATransaction.setAnimationTimingFunction(
        CAMediaTimingFunction(name: .easeOut)
    )
    CATransaction.setCompletionBlock {
        print("All animations completed")
    }

    // Tutte le modifiche all’interno della transazione vengono animate con durata 1.5
    layer1.opacity = 0.3
    layer2.position = CGPoint(x: 200, y: 300)
    layer3.backgroundColor = UIColor.systemRed.cgColor

    CATransaction.commit()
}

// Disattivazione dell’animazione implicita
func updateWithoutAnimation() {
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    layer.frame = newFrame // senza animazione
    CATransaction.commit()
}

// Animazione delle proprietà di 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()
}

Esempi di codice Swift

Core Animation si integra con UIKit attraverso il layer UIView. L’esempio seguente mostra un’animazione CAShapeLayer — un progresso circolare con animazione della lunghezza dell’arco e rotazione del layer tramite 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 proprietà strokeEnd da 0 a 1, creando un effetto di “riempimento” del progresso circolare. CATransaction con durata 0,6 e easeOut rende l’animazione fluida. layer.lineCap = .round aggiunge estremità arrotondate alla linea per un aspetto più pulito.

Domande frequenti

Qual è la differenza tra Core Animation e UIView.animate?

Core Animation funziona a livello di CALayer e viene controllato tramite CABasicAnimation e CATransaction. UIView.animate è un wrapper di alto livello attorno a Core Animation che crea automaticamente CABasicAnimation per le proprietà di UIView. Core Animation offre più controllo: keyPath, timingFunction, fillMode, raggruppamento tramite CATransaction.

Cos’è l’animazione implicita in Core Animation?

L’animazione implicita è un’animazione automatica che si verifica quando una proprietà animabile di CALayer viene modificata al di fuori di un blocco di animazione. Ad esempio, layer.opacity = 0,5 crea una CABasicAnimation con durata 0,25 s. Le animazioni implicite sono gestite tramite CATransaction e possono essere disabilitate usando setDisableActions(true).

Come animare una proprietà personalizzata di CALayer?

Per le proprietà personalizzate, implementare action(forKey:) in CALayer e restituire una CAAnimation. In alternativa, utilizzare CALayer.display() per il disegno manuale con animazione tramite CADisplayLink. Per le proprietà che supportano CABasicAnimation, è sufficiente specificare il keyPath come stringa.

Perché CALayer è più efficiente di UIView per l’animazione?

CALayer è più leggero di UIView: non ha gestori di eventi (touches, gestures), non partecipa ad Auto Layout e non supporta l’accessibilità. Un CALayer tipico occupa ~100 byte contro ~300+ di UIView. Core Animation elabora i layer nel render server sulla GPU senza bloccare il thread principale.

Riepilogo

  • Core Animation — framework di basso livello di Apple per l’animazione CALayer con rendering GPU
  • CALayer — classe base con oltre 60 proprietà animabili, supporta CAShapeLayer, CAGradientLayer, CATextLayer
  • CABasicAnimation — animazione di singola proprietà con fromValue/toValue, aggiunta tramite layer.add(animation, forKey:)
  • CATransaction — raggruppamento di animazioni con duration, timingFunction, completionBlock condivisi
  • Animazione implicita — animazione automatica al cambiamento delle proprietà di CALayer (durata 0,25 s)
  • Presentation layer — stato corrente del layer durante l’animazione, utilizzato per leggere i valori intermedi
  • Prestazioni — fino a 120 FPS su ProMotion, fino a 1000 layer a 60 FPS, 4 byte/pixel

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.

Discuti il progetto

Leggi anche