Layer — je abstrakce grafického obsahu, která spravuje vizuální reprezentaci prvků rozhraní v mobilních aplikacích. Na rozdíl od UIView, layer nezpracovává události dotyku a neúčastní se Auto Layout — jeho úkolem je výhradně vykreslování, animace a kompozice pixelů. Podle Apple QuartzCore Documentation, 2025, každý UIView v iOS má přidružený CALayer, který ve skutečnosti spravuje kreslení a animaci. Pochopení struktury vrstev umožňuje vývojáři řídit výkon vykreslování na úrovni jednotlivých pixelů.
Hlavní
Layer — je nízkoúrovňový objekt grafického systému, který ukládá rastrový obrázek fragmentu obrazovky a spravuje jeho vizuální atributy: polohu, velikost, rotaci, průhlednost, stín a barvu. V iOS má každý UIView vestavěný CALayer, přístupný přes vlastnost layer. Vývojář může pracovat přímo s layerem, obejít UIView, pro jemné doladění vykreslování.
Architektura vrstev následuje vzor Model-View-Controller, kde CALayer funguje jako Model — ukládá stav vizuálních vlastností. Core Animation je Controller, který spravuje animaci přechodu mezi stavy. View (UIView) — volitelný obal přidávající zpracování dotyků a účast v Auto Layout.
Podle Apple WWDC 2024, moderní pipeline vykreslování iOS používá Metal pro kompozici vrstev. Každý CALayer je kreslen do samostatného bufferu, poté Core Animation provádí sloučení všech bufferů do finálního obrazu s ohledem na průhlednost a režimy míchání.
V Android jsou obdobou vrstev View a Drawable pozadí, ale přímá práce s grafickými vrstvami je dostupná přes Canvas a RenderNode v Android 10+. Porozumění konceptu layer je důležité pro optimalizaci vykreslování na obou platformách.
Hlavní rozdíl je v oblasti odpovědnosti. View odpovídá za uživatelský vstup (dotyk, gesta), umístění (Auto Layout, frame) a životní cyklus. Layer odpovídá výhradně za vizuální reprezentaci: vykreslování obsahu, animaci vlastností a kompozici s ostatními vrstvami.
Toto oddělení umožňuje cachovat rastrovou reprezentaci vrstvy nezávisle na View. Pokud se vrstva nemění, Core Animation používá zacchovaný snímek bez volání drawRect. Pro statické prvky to přináší významný nárůst výkonu bez změny kódu.
iOS poskytuje bohatou hierarchii tříd dědících z CALayer. Každá podtřída je optimalizována pro konkrétní scénář: zobrazení textu, vektorové grafiky, gradientů nebo 3D transformací. Volba správného typu vrstvy přímo ovlivňuje výkon vykreslování.
V Android je koncept vrstev implementován přes RenderNode, ViewLayer a HardwareRenderer. Počínaje Android 5.0 (API 21) je každý View vykreslován do vlastní vrstvy hardwarové akcelerace, což umožňuje provádět animace bez volání onDraw.
Další flexibilitu v iOS poskytují CAReplicatorLayer a CAEmitterLayer. První se používá pro vytváření opakujících se vzorů, druhý — pro částicové systémy. Oba pracují výhradně na GPU, což umožňuje vytvářet složité vizuální efekty bez ztráty výkonu.
Hierarchie vrstev v iOS je postavena na principu stromu: každý CALayer může obsahovat mnoho podřízených sublayerů. Všechny transformace aplikované na nadřazenou vrstvu — měřítko, rotace, posun — se automaticky aplikují na podřízené prvky. To zajišťuje konzistenci vizuální reprezentace během animací.
Kompozice scény je prováděna Core Animation v následujícím pořadí: nejprve se vykreslí pozadí (background), poté každá podřízená vrstva v pořadí přidávání zdola nahoru. Pro každou vrstvu Core Animation kontroluje vlastnosti průhlednosti, masek a režimů míchání, poté provádí sloučení (compositing) do finálního snímku.
Podle Apple Documentation, kompozice vrstvy s opaque = true a bez alfa kanálu probíhá bez dalších průchodů — GPU jednoduše kopíruje pixely přes předchozí vrstvu. Pokud vrstva obsahuje průhlednost, GPU provádí alfa-blending, což vyžaduje další výpočetní zdroje.
V Android kompozice vrstev probíhá přes SurfaceFlinger — systémovou službu, která přijímá buffery od každé aplikace a slučuje je s ohledem na z-pořadí. Každé Window v Android je samostatný Surface, který může obsahovat více grafických vrstev.
CALayer.mask — vlastnost, která umožňuje aplikovat na vrstvu masku libovolného tvaru. Maska může být jakýkoli jiný CALayer — například CAShapeLayer s kruhovým path nebo CAGradientLayer pro vytvoření plynulého přechodu průhlednosti. Použití masek zvyšuje zátěž GPU, protože vyžaduje další průchod vykreslování pro výpočet alfa hodnot každého pixelu.
Pro jednoduché ořezávání podle obdélníkových hranic se doporučuje použít cornerRadius a masksToBounds. Na rozdíl od masek přes vlastnost mask, cornerRadius je zpracováván hardwarově ve fázi rasterizace a nevyžaduje další průchod.
shouldRasterize — klíčová vlastnost CALayer pro optimalizaci výkonu. Když je shouldRasterize nastaven na true, Core Animation vykreslí vrstvu a všechny její sublayery do samostatného rastrového bufferu (offscreen buffer). Při následujících snímcích se místo opakovaného vykreslování použije zacchovaný rastrový obrázek.
Cachování je efektivní pro statické nebo zřídka se měnící vrstvy: stíny, gradienty, text se zaoblenými rohy. Avšak pro často aktualizované vrstvy (animace, video, scroll) může rasterizace zhoršit výkon, protože každý snímek vyžaduje regeneraci cache.
Podle výzkumu Objc.io, správné použití shouldRasterize na iPad Pro snižuje dobu vykreslování složité obrazovky z 25 ms na 8 ms — více než třikrát. Klíčová podmínka: vrstva by se neměla měnit častěji než jednou za 3-5 snímků.
První příklad demonstruje nastavení základních vizuálních vlastností CALayer v Swift — zaoblení rohů, stín a okraj:
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
}
}
Druhý příklad — vytvoření animace vrstvy v Swift pomocí CABasicAnimation. Animuje se vlastnost position bez účasti 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")
Třetí příklad — práce s RenderNode v Kotlin na Android. RenderNode — přímá obdoba CALayer, umožňující práci s grafickými vrstvami na úrovni 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
}
Často kladené otázky
UIView — je obal kolem CALayer, který přidává zpracování dotyků a účast v Auto Layout. Layer se zabývá pouze vykreslováním a animací. Práce přímo s CALayer je možná, ale pro zpracování vstupních událostí je potřeba UIView.
shouldRasterize zapíná cachování vrstvy do samostatného offscreen bufferu. Používejte pro statické nebo zřídka se měnící prvky se stíny nebo složitou kompozicí. Nepoužívejte pro často animované vrstvy — regenerace cache bude dražší než přímé vykreslování.
Nastavte vlastnost cornerRadius pro zaoblení rohů a masksToBounds = true pro ořezání obsahu podle hranic vrstvy. Pro stín musí být masksToBounds false, jinak bude stín ořezán — v tomto případě použijte samostatnou vrstvu pro stín.
Ano, RenderNode v Android 10+ poskytuje podobnou funkcionalitu: správu polohy, měřítka, rotace a průhlednosti na úrovni grafické vrstvy. Canvas a HardwareRenderer zajišťují vykreslování přes GPU. Architektonicky však Android neodděluje View a vrstvu tak striktně jako iOS.
Stín v CALayer se počítá přes shadowPath nebo automaticky na základě alfa kanálu. Automatický výpočet vyžaduje průchod všemi pixely vrstvy, což je nákladné. Zadejte explicitní shadowPath — obdélník nebo UIBezierPath — to umožní GPU vypočítat stín bez procházení obsahu.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také