Core Animation je nízkoúrovňový animační framework Apple, pracující na úrovni CALayer a zajišťující vykreslování obsahu na GPU. Core Animation je základem všech animací v iOS a macOS: UIKit, AppKit, SceneKit a SpriteKit jsou postaveny na něm. Článek vysvětluje architekturu CALayer, CABasicAnimation, CATransaction a praktické techniky.
Hlavní body
Core Animation je grafický framework Apple, který se objevil v Mac OS X 10.5 Leopard (2007) a byl portován na iOS od první verze iPhone OS (2007). Core Animation spravuje kompozici, animaci a vykreslování vrstev (CALayer) na GPU. Každý UIView v iOS má vestavěný CALayer (view.layer), přes který probíhá veškeré vykreslování.
Core Animation pracuje na principu implicit animation: některé změny vlastností CALayer jsou animovány automaticky (animuje CABasicAnimation pro position, bounds, opacity, backgroundColor). Implicit-animace standardně používají CATransaction s délkou 0.25 sekundy a křivkou easeInOut.
Podle dat Apple WWDC 2024 zpracovává Core Animation až 120 FPS na zařízeních s ProMotion, využívajících Metal pro GPU vykreslování. Velikost typické vrstvy v paměti je 4 bajty na pixel (RGBA) + režie ~100 bajtů na vrstvu. Pro stabilních 60 FPS se doporučuje maximálně 1000 vrstev na obrazovku.
CALayer základ Core Animation. Každý CALayer obsahuje bitmapový obsah (nebo odkaz na GPU texturu) a definuje geometrii (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). Vrstva nezpracovává dotykové události o to se stará UIView/UIScrollView. Vrstvy tvoří hierarchii (layer tree) zrcadlící hierarchii pohledů.
Core Animation podporuje tři stromy vrstev: model layer tree (skutečné vlastnosti), presentation layer tree (aktuální zobrazení během animace) a render tree (data pro GPU). Presentation layer se používá pro čtení průběžných hodnot animace v reálném čase.
CALayer má specializované podtřídy: CAShapeLayer (vektorová grafika), CAGradientLayer (gradient), CATextLayer (text), CATiledLayer (velké obrázky rozdělené na dlaždice), CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer je nejoblíbenější pro vlastní animace díky podpoře CGPath a animace strokeStart/strokeEnd.
CABasicAnimation je podtřída CAAnimation animující jednu vlastnost CALayer od počáteční hodnoty (fromValue) do konečné hodnoty (toValue) nebo relativní změny (byValue). Animace je přidána k vrstvě metodou layer.add(animation, forKey:) a provádí se v render serveru bez účasti aplikace na každém snímku.
Klíč (keyPath) je řetězec ukazující na vlastnost: opacity, position, bounds, transform.rotation.z, cornerRadius, shadowOpacity atd. Core Animation podporuje 60+ animovatelných keyPath. Pro vlastní vlastnosti se používají CATransaction a presentation layer.
import QuartzCore
// CABasicAnimation pro opacity a 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. Animace průhlednosti
let fadeAnim = CABasicAnimation(keyPath: "opacity")
fadeAnim.fromValue = 1.0
fadeAnim.toValue = 0.2
fadeAnim.duration = 2.0
fadeAnim.autoreverses = true
fadeAnim.repeatCount = .infinity
// 2. Animace zaoblení rohů
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")
}
// Animace position s 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 // aktualizujeme model layer
}Důležité: CABasicAnimation je dočasné zobrazení (presentation layer). Po dokončení animace se vrstva vrátí k původním hodnotám model layer. Pro upevnění konečného stavu nastavte isRemovedOnCompletion = false, fillMode = .forwards a aktualizujte model layer na konečné hodnoty.
CATransaction je mechanismus pro seskupování Core Animation animací do jedné transakce. CATransaction.begin() a CATransaction.commit() definují hranice transakce. Uvnitř transakce lze nastavit společné parametry: duration, timingFunction, completionBlock, disableActions. CATransaction je základem implicit-animací CALayer.
Implicit animation funguje, když je vlastnost CALayer změněna mimo blok animace: layer.opacity = 0.5. Core Animation automaticky vytvoří CABasicAnimation s duration z aktuálního CATransaction (výchozí 0.25 s). Pro vypnutí implicit-animace použijte CATransaction.setDisableActions(true).
// CATransaction seskupení a dokončení
func groupedAnimation() {
CATransaction.begin()
CATransaction.setAnimationDuration(1.5)
CATransaction.setAnimationTimingFunction(
CAMediaTimingFunction(name: .easeOut)
)
CATransaction.setCompletionBlock {
print("All animations completed")
}
// Všechny změny uvnitř transakce jsou animovány s duration 1.5
layer1.opacity = 0.3
layer2.position = CGPoint(x: 200, y: 300)
layer3.backgroundColor = UIColor.systemRed.cgColor
CATransaction.commit()
}
// Vypnutí implicit-animace
func updateWithoutAnimation() {
CATransaction.begin()
CATransaction.setDisableActions(true)
layer.frame = newFrame // bez animace
CATransaction.commit()
}
// Animace vlastností 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()
}Core Animation se integruje s UIKit přes vrstvu UIView. Níže uvedený příklad demonstruje animaci CAShapeLayer kruhový ukazatel průběhu s animací délky oblouku a rotací vrstvy přes CABasicAnimation.
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 animuje vlastnost strokeEnd od 0 do 1, čímž vytváří efekt „naplnění“ kruhového ukazatele průběhu. CATransaction s délkou 0.6 a easeOut činí animaci plynulou. layer.lineCap = .round přidává zaoblené konce čáry pro úhlednější vzhled.
Často kladené otázky
Core Animation pracuje na úrovni CALayer a je řízena přes CABasicAnimation, CATransaction. UIView.animate je vysokoúrovňový obal nad Core Animation, automaticky vytvářející CABasicAnimation pro vlastnosti UIView. Core Animation poskytuje větší kontrolu: keyPath, timingFunction, fillMode, seskupení přes CATransaction.
Implicit animation je automatická animace při změně animovatelné vlastnosti CALayer mimo blok animace. Například layer.opacity = 0.5 vytvoří CABasicAnimation s délkou 0.25 s. Implicit-animace jsou řízeny přes CATransaction a vypínají se přes setDisableActions(true).
Pro vlastní vlastnosti implementujte action(forKey:) v CALayer a vraťte CAAnimation. Nebo použijte CALayer.display() pro ruční vykreslování s animací přes CADisplayLink. Pro vlastnosti podporující CABasicAnimation stačí uvést keyPath jako řetězec.
CALayer je lehčí než UIView: nemá obsluhy událostí (touches, gesta), neúčastní se Auto Layout a nepodporuje accessibility. Typický CALayer zabírá ~100 bajtů oproti ~300+ u UIView. Core Animation zpracovává vrstvy v render serveru na GPU bez blokování main thread.
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é