CAShapeLayer — cos'è, proprietà e creazione di forme

Autore: IT Sectr Pubblicato: 2026-06-12 Tempo di lettura: 10 min

CAShapeLayer è una sottoclasse di CALayer progettata per il rendering accelerato via hardware di tracciati vettoriali sulla GPU. A differenza di CALayer base, che lavora con immagini raster tramite contents, CAShapeLayer renderizza forme arbitrarie definite tramite CGPath senza creare un buffer offscreen separato. Secondo Apple QuartzCore Documentation, 2025, CAShapeLayer utilizza l'accelerazione hardware per l'anti-aliasing dei bordi e supporta l'animazione di path, strokeStart e strokeEnd. È uno strumento standard per creare icone, indicatori di progresso e maschere in iOS.

Punti Chiave

  • CAShapeLayer — una sottoclasse di CALayer per renderizzare forme vettoriali sulla GPU tramite CGPath.
  • Il rendering del tracciato viene eseguito via hardware senza creare un buffer raster intermedio — è più veloce di Core Graphics.
  • Proprietà fillColor, strokeColor, lineWidth, lineCap, lineJoin controllano l'aspetto della forma.
  • L'animazione di path consente di trasformare dolcemente una forma in un'altra — una capacità chiave per le animazioni UI.
  • strokeStart e strokeEnd vengono animati per creare un effetto di disegno del tracciato — ideale per indicatori di caricamento.

Cos'è CAShapeLayer?

CAShapeLayer è un layer specializzato per il rendering di grafica vettoriale, introdotto in iOS 3.0. A differenza di CALayer, che memorizza un'immagine raster, CAShapeLayer memorizza una descrizione matematica di un tracciato — CGPath — e lo renderizza direttamente sulla GPU. Ciò consente di ridimensionare la forma senza perdita di qualità e di animare le sue proprietà senza ridisegnare il contenuto.

Architettonicamente, CAShapeLayer eredita tutte le capacità di CALayer: ombre, bordi, trasformazioni, maschere. Ma aggiunge proprietà specifiche per lavorare con i tracciati: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, miterLimit, strokeStart, strokeEnd e fillRule. Ciascuna di queste proprietà può essere animata tramite CABasicAnimation.

Secondo Apple Documentation, CAShapeLayer utilizza l'accelerazione hardware per il rendering. A differenza del disegno tramite Core Graphics in drawRect:, dove la CPU renderizza il tracciato in un contesto raster, CAShapeLayer invia comandi direttamente alla GPU tramite Metal. Il risultato è prestazioni più elevate, specialmente durante l'animazione.

CAShapeLayer è particolarmente utile per elementi dell'interfaccia che cambiano forma in risposta alle azioni dell'utente: indicatori di progresso, grafici, icone della barra delle schede, maschere per animazioni di rivelazione del contenuto.

Come CAShapeLayer renderizza un tracciato sulla GPU

Il processo di rendering di CAShapeLayer differisce da quello di CALayer base. Invece di memorizzare un buffer raster con pixel, CAShapeLayer passa una descrizione dei vertici del tracciato alla GPU — un insieme di punti, curve di Bézier e segmenti di linea. La GPU rasterizza questo tracciato in un unico passaggio, applicando i colori di riempimento e tratto nella fase dello shader di frammento.

Questo approccio offre due vantaggi: ridimensionamento senza perdita di qualità (la grafica vettoriale rimane nitida a qualsiasi risoluzione) e animazione efficiente — quando il tracciato cambia, la GPU ricalcola solo i pixel modificati, non l'intero schermo.

Principali proprietà di CAShapeLayer

path — la proprietà centrale di CAShapeLayer, che accetta un CGPath. Il tracciato può contenere linee, archi, curve di Bézier e rettangoli. Viene creato tramite UIBezierPath in Swift o CGPath in Core Graphics. Esempio: UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath crea un rettangolo arrotondato.

  • fillColor — il colore di riempimento del tracciato chiuso (CGColor). Se nil, nessun riempimento. Supporta l'animazione.
  • strokeColor — il colore del tratto del tracciato. Si anima insieme a lineWidth, creando un effetto di disegno del tracciato.
  • lineWidth — lo spessore della linea del tratto in punti. Il default è 1.0. Può essere animato.
  • lineCap — lo stile di terminazione della linea: .butt (taglio netto), .round (arrotondato), .square (rettangolare con sporgenza).
  • lineJoin — lo stile di giunzione delle linee: .miter (angolo acuto), .round (arrotondato), .bevel (smussato).
  • strokeStart e strokeEnd — la frazione del tracciato disegnato da 0.0 a 1.0. Animare strokeEnd crea un effetto di rivelazione graduale.
  • fillRule — la regola di riempimento per tracciati che si intersecano: .nonZero (default) o .evenOdd.
  • miterLimit — la lunghezza massima del miter quando lineJoin = .miter. Previene angoli infinitamente lunghi.

La proprietà lineDashPattern consente di creare linee tratteggiate. Accetta un array di numeri: [6, 3] significa 6 punti di tratto e 3 punti di spazio. lineDashPhase imposta l'offset del pattern e può essere animato per un effetto di tratto in movimento.

CAShapeLayer vs CALayer: quando scegliere ciascuno

La scelta tra CAShapeLayer e CALayer base dipende dal tipo di contenuto. Se l'elemento è un'area rettangolare con sfondo, bordo e ombra — CALayer è sufficiente. Se l'elemento ha una forma arbitraria, richiede animazione del tracciato o ridimensionamento senza perdita di qualità — CAShapeLayer è preferibile.

Anche le prestazioni differiscono. CALayer con cornerRadius e masksToBounds crea un buffer offscreen per il ritaglio del contenuto, aggiungendo 2–5 ms per fotogramma. CAShapeLayer non richiede un buffer offscreen — il ritaglio viene eseguito a livello dello shader di vertice. Per elementi con maschere complesse, CAShapeLayer può essere 2–3 volte più veloce.

  • CALayer: elementi rettangolari, foto, video, contenuti con angoli arrotondati (cornerRadius), ombre, bordi.
  • CAShapeLayer: icone, grafici, barre di progresso, maschere di forma arbitraria, tracciati animati, forme per animazioni di rivelazione.
  • CATextLayer: testo che richiede rendering subpixel e caching dei glifi.
  • CAGradientLayer: riempimenti sfumati — combinato con CAShapeLayer tramite mask per creare forme con gradiente.

Combinare CAShapeLayer con altri layer è un pattern comune. Ad esempio, CAGradientLayer usa CAShapeLayer come maschera per creare una forma con riempimento sfumato. Questo approccio offre sia qualità vettoriale che riempimento sfumato senza perdita di prestazioni.

Animazione di CAShapeLayer: path e stroke

L'animazione di path è una delle funzionalità più potenti di CAShapeLayer. Se entrambi i tracciati (iniziale e finale) hanno lo stesso numero di punti di controllo e segmenti, Core Animation esegue un'interpolazione fluida tra di essi. Il risultato è un effetto di morphing da una forma all'altra.

Condizione di compatibilità del tracciato: l'UIBezierPath iniziale e finale devono avere la stessa struttura — il numero di chiamate moveTo, addLine, addCurve e addQuadCurve deve corrispondere. Se la struttura è diversa, l'animazione sarà istantanea, senza interpolazione.

Secondo Apple WWDC 2024, la combinazione di strokeStart e strokeEnd è il pattern di animazione CAShapeLayer più utilizzato. Animare strokeEnd da 0.0 a 1.0 crea un effetto di disegno del tracciato dall'inizio alla fine. Viene utilizzato negli indicatori di caricamento, nelle animazioni di rivelazione dei grafici e nelle transizioni personalizzate tra schermate.

Per creare un effetto pulsante, animate strokeEnd e opacity contemporaneamente con diverse funzioni di temporizzazione. Per un effetto di formiche in marcia, animate lineDashPhase con un lineDashPattern fisso. Entrambe le tecniche sono implementate tramite CABasicAnimation senza coinvolgimento della CPU.

Animazione come maschera

CAShapeLayer è spesso usato come maschera per altri layer. Ad esempio, per l'animazione di rivelazione del contenuto: inizialmente, mask.path è un rettangolo di dimensioni zero, e quello finale è a grandezza naturale. Core Animation interpola il tracciato e il contenuto si rivela dolcemente.

Questo pattern viene utilizzato in iOS per l'animazione di espansione delle carte, la presentazione di finestre modali e le transizioni tra controller di visualizzazione. A differenza dell'animazione alpha, l'animazione della maschera CAShapeLayer offre un effetto di rivelazione più naturale con forme arbitrarie.

Esempi di codice con CAShapeLayer in Swift

Il primo esempio — creazione di un indicatore di progresso circolare con animazione strokeEnd. Questo è un elemento UI standard che dimostra le capacità principali di CAShapeLayer:

swift
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
}

// Anima al 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)

Il secondo esempio — animazione di morphing tra un cerchio e un quadrato. Entrambi gli UIBezierPath hanno una struttura compatibile:

swift
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")

Il terzo esempio — una maschera CAShapeLayer per l'animazione di rivelazione del contenuto. La maschera si espande dal centro verso i bordi:

swift
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
}

Domande Frequenti

In cosa CAShapeLayer differisce dal disegno in drawRect?

drawRect utilizza la CPU per renderizzare in un contesto raster — è lento per le animazioni. CAShapeLayer renderizza il tracciato sulla GPU, offrendo 60 FPS durante le animazioni di path, strokeEnd e trasformazioni. Inoltre, CAShapeLayer non richiede ridisegno quando viene ridimensionato — la forma si ridimensiona vettorialmente.

Perché l'animazione di path non funziona in modo fluido?

Un'animazione fluida del tracciato richiede struttura identica dell'UIBezierPath iniziale e finale. Il numero di chiamate moveTo, addLine, addCurve deve corrispondere. Utilizzare UIBezierPath con lo stesso numero di segmenti per le forme iniziale e finale.

Come creare una linea tratteggiata in CAShapeLayer?

Impostare lineDashPattern — un array di numeri che alternano lunghezze di tratto e spazio. Ad esempio, [8, 4] crea tratti da 8pt con spazi da 4pt. Per un effetto di formiche in marcia, animare lineDashPhase tramite CABasicAnimation con una funzione di temporizzazione lineare.

CAShapeLayer può essere usato come maschera?

Sì, questo è uno dei casi d'uso principali. Assegnare CAShapeLayer alla proprietà mask di qualsiasi CALayer, inclusi CAGradientLayer e altre sottoclassi. Animare il tracciato della maschera crea un effetto di rivelazione fluida del contenuto attraverso una forma arbitraria.

Come riempire una forma con un gradiente tramite CAShapeLayer?

Creare un CAGradientLayer e impostare il suo mask = CAShapeLayer con il tracciato desiderato. Il gradiente sarà visibile solo all'interno del tracciato della maschera. Questo pattern combina i vantaggi della forma vettoriale di CAShapeLayer e il riempimento sfumato di CAGradientLayer.

Riepilogo

  • CAShapeLayer — una sottoclasse di CALayer per il rendering accelerato via hardware di tracciati vettoriali sulla GPU tramite CGPath.
  • Proprietà chiave: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, strokeStart, strokeEnd.
  • L'animazione di path crea morphing di forme — richiede struttura identica dei tracciati iniziale e finale.
  • L'animazione di strokeEnd — un pattern standard per indicatori di progresso e disegno di tracciati.
  • CAShapeLayer non richiede buffer offscreen per la mascheratura, a differenza di CALayer con masksToBounds.
  • Utilizzato come maschera per CAGradientLayer, creando forme con riempimento sfumato.
  • Per linee tratteggiate, utilizzare lineDashPattern con animazione lineDashPhase per un effetto di movimento.

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