Layer è un'astrazione di contenuto grafico che gestisce la rappresentazione visiva degli elementi dell'interfaccia nelle applicazioni mobili. A differenza di UIView, layer non elabora eventi tattili e non partecipa ad Auto Layout — il suo unico scopo è rendering, animazione e composizione di pixel. Secondo Apple QuartzCore Documentation, 2025, ogni UIView in iOS ha un CALayer associato che gestisce effettivamente il disegno e l'animazione. Comprendere la struttura dei layer permette allo sviluppatore di controllare le prestazioni di rendering a livello di singoli pixel.
Punti chiave
Layer è un oggetto di basso livello del sistema grafico che memorizza un'immagine bitmap di un frammento di schermo e gestisce i suoi attributi visivi: posizione, dimensione, rotazione, opacità, ombra e colore. In iOS, ogni UIView ha un CALayer integrato accessibile tramite la proprietà layer. Uno sviluppatore può lavorare direttamente con il layer, bypassando UIView, per un controllo granulare del rendering.
L'architettura dei layer segue il pattern Model-View-Controller, dove CALayer agisce come Modello — memorizza lo stato delle proprietà visive. Core Animation è il Controller che gestisce le transizioni di animazione tra gli stati. View (UIView) è un wrapper opzionale che aggiunge la gestione tattile e la partecipazione ad Auto Layout.
Secondo Apple WWDC 2024, la pipeline di rendering moderna di iOS utilizza Metal per la composizione dei layer. Ogni CALayer viene renderizzato in un buffer separato, dopo di che Core Animation compone tutti i buffer nell'immagine finale, tenendo conto dell'opacità e delle modalità di fusione.
In Android, l'analogo dei layer è View e Drawable di sfondo, ma il lavoro diretto con i layer grafici è disponibile tramite Canvas e RenderNode in Android 10+. Comprendere il concetto di layer è importante per ottimizzare il rendering su entrambe le piattaforme.
La differenza principale risiede nell'area di responsabilità. View gestisce l'input dell'utente (tocchi, gesti), il posizionamento (Auto Layout, frame) e il ciclo di vita. Layer è esclusivamente responsabile della presentazione visiva: rendering del contenuto, animazione delle proprietà e composizione con altri layer.
Questa separazione permette di memorizzare nella cache la rappresentazione bitmap del layer indipendentemente dalla View. Se il layer non cambia, Core Animation utilizza il frame cache senza chiamare drawRect. Per gli elementi statici, questo fornisce un aumento significativo delle prestazioni senza modifiche al codice.
iOS fornisce una ricca gerarchia di classi che ereditano da CALayer. Ogni sottoclasse è ottimizzata per uno scenario specifico: visualizzazione di testo, grafica vettoriale, gradienti o trasformazioni 3D. La scelta del tipo di layer corretto influisce direttamente sulle prestazioni di rendering.
In Android, il concetto di layer è implementato tramite RenderNode, ViewLayer e HardwareRenderer. A partire da Android 5.0 (API 21), ogni View viene renderizzata nel proprio layer di accelerazione hardware, consentendo animazioni senza chiamare onDraw.
Flessibilità aggiuntiva in iOS è fornita da CAReplicatorLayer e CAEmitterLayer. Il primo viene utilizzato per creare pattern ripetitivi, il secondo per sistemi di particelle. Entrambi funzionano esclusivamente sulla GPU, consentendo di creare effetti visivi complessi senza perdita di prestazioni.
La gerarchia dei layer in iOS segue una struttura ad albero: ogni CALayer può contenere più sublayer figli. Tutte le trasformazioni applicate al layer genitore — scala, rotazione, traslazione — vengono automaticamente applicate agli elementi figli. Questo garantisce coerenza visiva durante le animazioni.
La composizione della scena viene eseguita da Core Animation nel seguente ordine: prima viene renderizzato lo sfondo, poi ogni layer figlio in ordine dal basso verso l'alto. Per ogni layer, Core Animation controlla le proprietà di opacità, maschere e modalità di fusione, quindi le compone nel frame finale.
Secondo Apple Documentation, la composizione di un layer con opaque = true e senza canale alfa viene eseguita senza passaggi aggiuntivi — la GPU copia semplicemente i pixel sopra il layer precedente. Se il layer ha trasparenza, la GPU esegue la fusione alfa, che richiede risorse computazionali aggiuntive.
In Android, la composizione dei layer viene eseguita tramite SurfaceFlinger — un servizio di sistema che riceve buffer da ciascuna applicazione e li compone secondo l'ordine z. Ogni Window in Android è una Surface separata che può contenere più layer grafici.
CALayer.mask — una proprietà che consente di applicare una maschera di forma arbitraria a un layer. La maschera può essere qualsiasi altro CALayer — ad esempio, CAShapeLayer con un percorso circolare o CAGradientLayer per creare una transizione morbida di opacità. L'uso delle maschere aumenta il carico della GPU poiché richiede un passaggio di rendering aggiuntivo per calcolare i valori alfa di ciascun pixel.
Per il ritaglio rettangolare semplice, si consiglia di utilizzare cornerRadius e masksToBounds. A differenza delle maschere tramite la proprietà mask, cornerRadius viene elaborato dall'hardware nella fase di rasterizzazione e non richiede un passaggio aggiuntivo.
shouldRasterize è una proprietà chiave di CALayer per l'ottimizzazione delle prestazioni. Quando shouldRasterize è impostato su true, Core Animation renderizza il layer e tutti i suoi sublayer in un buffer offscreen separato. Nei frame successivi, l'immagine bitmap cache viene utilizzata invece di ri-renderizzare.
Il caching è efficace per layer statici o che cambiano raramente: ombre, gradienti, testo con angoli arrotondati. Tuttavia, per layer aggiornati frequentemente (animazione, video, scorrimento), la rasterizzazione può degradare le prestazioni poiché ogni frame richiede la rigenerazione della cache.
Secondo una ricerca di Objc.io, l'uso corretto di shouldRasterize su iPad Pro riduce il tempo di rendering di uno schermo complesso da 25 ms a 8 ms — più di tre volte. La condizione chiave è che il layer non dovrebbe cambiare più di una volta ogni 3–5 frame.
Il primo esempio mostra l'impostazione delle proprietà visive di base di CALayer in Swift — angoli arrotondati, ombra e bordo:
import UIKit
class StyledView: UIView {
override func awakeFromNib() {
super.awakeFromNib()
layer.cornerRadius = 12
layer.masksToBounds = false
layer.shadowColor = UIColor.darkGray.cgColor
layer.shadowOpacity = 0.3
layer.shadowOffset = CGSize(width: 0, height: 4)
layer.shadowRadius = 8
}
}
Il secondo esempio — creazione di un'animazione di layer in Swift utilizzando CABasicAnimation. La proprietà position viene animata senza il coinvolgimento di UIView:
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = NSValue(cgPoint: CGPoint(x: 0, y: 0))
animation.toValue = NSValue(cgPoint: CGPoint(x: 150, y: 300))
animation.duration = 1.0
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
targetLayer.add(animation, forKey: "moveAnimation")
Il terzo esempio — lavoro con RenderNode in Kotlin su Android. RenderNode è un analogo diretto di CALayer, che consente di operare con layer grafici a livello di Canvas:
import android.graphics.renderer.RenderNode
fun createLayer(): RenderNode {
val node = RenderNode("customLayer")
node.setPosition(0, 0, 300, 200)
node.setScaleX(1.5f)
node.setScaleY(1.5f)
val canvas = node.beginRecording()
canvas.drawColor(android.graphics.Color.BLUE)
node.endRecording()
return node
}
Domande frequenti
UIView è un wrapper attorno a CALayer che aggiunge la gestione tattile e la partecipazione ad Auto Layout. Layer si occupa solo di rendering e animazione. Puoi lavorare direttamente con CALayer, ma UIView è necessario per elaborare gli eventi di input.
shouldRasterize abilita il caching del layer in un buffer offscreen separato. Usalo per elementi statici o che cambiano raramente con ombre o composizione complessa. Non usarlo per layer animati frequentemente — la rigenerazione della cache sarà più costosa del rendering diretto.
Imposta la proprietà cornerRadius per arrotondare gli angoli e masksToBounds = true per ritagliare il contenuto ai limiti del layer. Per le ombre, masksToBounds deve essere false, altrimenti l'ombra verrà ritagliata — in questo caso, usa un layer separato per l'ombra.
Sì, RenderNode in Android 10+ fornisce funzionalità simili: gestione di posizione, scala, rotazione e opacità a livello di layer grafico. Canvas e HardwareRenderer forniscono rendering basato su GPU. Tuttavia, architetturalmente Android non separa View e layer in modo così rigoroso come iOS.
Un'ombra in CALayer viene calcolata tramite shadowPath o automaticamente in base al canale alfa. Il calcolo automatico richiede di attraversare tutti i pixel del layer, il che è costoso. Specifica un shadowPath esplicito — un rettangolo o UIBezierPath — questo permette alla GPU di calcolare l'ombra senza attraversare il contenuto.
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