Core Animation: podstawy, CALayer i animacja w iOS

Autor: IT Sectr Opublikowano: 2026-03-01 Czas czytania: 8 min

Core Animation – niskopoziomowy framework animacji Apple, działający na poziomie CALayer i zapewniający renderowanie treści na GPU. Core Animation jest podstawą wszystkich animacji w iOS i macOS: UIKit, AppKit, SceneKit i SpriteKit są zbudowane na jej bazie. Artykuł wyjaśnia architekturę CALayer, CABasicAnimation, CATransaction oraz praktyczne techniki.

Najważniejsze

  • CALayer – podstawowa klasa Core Animation do zarządzania wyświetlaniem treści na GPU
  • CABasicAnimation – prosta animacja jednej właściwości CALayer od fromValue do toValue
  • CATransaction – grupowanie animacji w jedną transakcję ze wspólnymi duration i completion
  • CAAnimation – abstrakcyjna klasa bazowa, z której dziedziczą CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup
  • Render server – oddzielny proces (backboardd), interpolujący klatki animacji na GPU

Czym jest Core Animation?

Core Animation – graficzny framework Apple, który pojawił się w Mac OS X 10.5 Leopard (2007) i został przeniesiony na iOS od pierwszej wersji iPhone OS (2007). Core Animation zarządza kompozycją, animacją i renderowaniem warstw (CALayer) na GPU. Każdy UIView w iOS ma wbudowaną warstwę CALayer (view.layer), przez którą odbywa się całe renderowanie.

Core Animation działa na zasadzie implicit animation: niektóre zmiany właściwości CALayer są animowane automatycznie (animują CABasicAnimation dla position, bounds, opacity, backgroundColor). Implicit-animacje używają CATransaction domyślnie z czasem trwania 0,25 sekundy i krzywą easeInOut.

Według danych Apple WWDC 2024, Core Animation przetwarza do 120 FPS na urządzeniach z ProMotion, wykorzystując Metal do renderowania na GPU. Rozmiar typowej warstwy w pamięci to 4 bajty na piksel (RGBA) + narzut ~100 bajtów na warstwę. Zaleca się nie więcej niż 1000 warstw na ekran dla stabilnych 60 FPS.

Architektura CALayer

CALayer – podstawa Core Animation. Każdy CALayer zawiera treść bitmapową (lub odnośnik do tekstury GPU) i określa geometrię (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). Warstwa nie obsługuje zdarzeń dotyku – odpowiada za to UIView/UIScrollView. Warstwy tworzą hierarchię (layer tree), odzwierciedlającą hierarchię widoków.

Core Animation obsługuje trzy drzewa warstw: model layer tree (rzeczywiste właściwości), presentation layer tree (bieżący stan podczas animacji) i render tree (dane dla GPU). Presentation layer jest używany do odczytywania pośrednich wartości animacji w czasie rzeczywistym.

Typy CALayer

CALayer ma wyspecjalizowane podklasy: CAShapeLayer (grafika wektorowa), CAGradientLayer (gradient), CATextLayer (tekst), CATiledLayer (duże obrazy podzielone na kafelki), CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer jest najpopularniejszy do niestandardowych animacji dzięki obsłudze CGPath i animacji strokeStart/strokeEnd.

CABasicAnimation – podstawowa animacja właściwości

CABasicAnimation – podklasa CAAnimation, animująca jedną właściwość CALayer od wartości początkowej (fromValue) do końcowej (toValue) lub względnej zmiany (byValue). Animacja jest dodawana do warstwy przez metodę layer.add(animation, forKey:) i wykonywana w render server bez udziału aplikacji na każdej klatce.

Klucz (keyPath) – ciąg znaków wskazujący właściwość: opacity, position, bounds, transform.rotation.z, cornerRadius, shadowOpacity itd. Core Animation obsługuje 60+ animowanych keyPath. Dla niestandardowych właściwości używa się CATransaction i presentation layer.

swift
import QuartzCore

// CABasicAnimation dla opacity i 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. Animacja przezroczystości
    let fadeAnim = CABasicAnimation(keyPath: "opacity")
    fadeAnim.fromValue = 1.0
    fadeAnim.toValue = 0.2
    fadeAnim.duration = 2.0
    fadeAnim.autoreverses = true
    fadeAnim.repeatCount = .infinity

    // 2. Animacja zaokrąglenia rogów
    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")
}

// Animacja position z 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 // aktualizujemy model layer
}

Ważne: CABasicAnimation to tymczasowe wyświetlanie (presentation layer). Po zakończeniu animacji warstwa wraca do początkowych wartości model layer. Aby zatrzymać stan końcowy, ustaw isRemovedOnCompletion = false, fillMode = .forwards i zaktualizuj model layer do wartości końcowych.

CATransaction – grupowanie animacji

CATransaction – mechanizm grupowania animacji Core Animation w jedną transakcję. CATransaction.begin() i CATransaction.commit() określają granice transakcji. Wewnątrz transakcji można ustawić wspólne parametry: duration, timingFunction, completionBlock, disableActions. CATransaction jest podstawą implicit-animacji CALayer.

Implicit animation działa, gdy właściwość CALayer jest zmieniana poza blokiem animacji: layer.opacity = 0.5. Core Animation automatycznie tworzy CABasicAnimation z czasem trwania z bieżącego CATransaction (domyślnie 0,25 s). Aby wyłączyć implicit-animacje, użyj CATransaction.setDisableActions(true).

swift
// CATransaction – grupowanie i completion
func groupedAnimation() {
    CATransaction.begin()
    CATransaction.setAnimationDuration(1.5)
    CATransaction.setAnimationTimingFunction(
        CAMediaTimingFunction(name: .easeOut)
    )
    CATransaction.setCompletionBlock {
        print("All animations completed")
    }

    // Wszystkie zmiany wewnątrz transakcji są animowane z czasem trwania 1.5
    layer1.opacity = 0.3
    layer2.position = CGPoint(x: 200, y: 300)
    layer3.backgroundColor = UIColor.systemRed.cgColor

    CATransaction.commit()
}

// Wyłączenie implicit-animacji
func updateWithoutAnimation() {
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    layer.frame = newFrame // bez animacji
    CATransaction.commit()
}

// Animacja właściwości 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()
}

Przykłady kodu w Swift

Core Animation integruje się z UIKit przez warstwę UIView. Poniższy przykład demonstruje animację CAShapeLayer – okrągły pasek postępu z animacją długości łuku i obrotem warstwy przez 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 animuje właściwość strokeEnd od 0 do 1, tworząc efekt „wypełniania” okrągłego paska postępu. CATransaction z czasem trwania 0,6 i easeOut sprawia, że animacja jest płynna. layer.lineCap = .round dodaje zaokrąglone końce linii dla bardziej estetycznego wyglądu.

Często zadawane pytania

Jaka jest różnica między Core Animation a UIView.animate?

Core Animation działa na poziomie CALayer i jest zarządzana przez CABasicAnimation, CATransaction. UIView.animate to wysokopoziomowe opakowanie nad Core Animation, automatycznie tworzące CABasicAnimation dla właściwości UIView. Core Animation daje więcej kontroli: keyPath, timingFunction, fillMode, grupowanie przez CATransaction.

Czym jest implicit animation w Core Animation?

Implicit animation to automatyczna animacja przy zmianie animowanej właściwości CALayer poza blokiem animacji. Na przykład layer.opacity = 0.5 tworzy CABasicAnimation z czasem trwania 0,25 s. Implicit-animacje są zarządzane przez CATransaction i wyłączane przez setDisableActions(true).

Jak animować niestandardową właściwość CALayer?

Dla niestandardowych właściwości zaimplementuj action(forKey:) w CALayer i zwróć CAAnimation. Możesz też użyć CALayer.display() do ręcznego renderowania z animacją przez CADisplayLink. Dla właściwości obsługujących CABasicAnimation wystarczy podać keyPath jako ciąg znaków.

Dlaczego CALayer jest wydajniejszy niż UIView do animacji?

CALayer jest lżejszy od UIView: nie ma obsługi zdarzeń (touches, gesty), nie uczestniczy w Auto Layout i nie wspiera accessibility. Typowy CALayer zajmuje ~100 bajtów wobec ~300+ dla UIView. Core Animation przetwarza warstwy w render server na GPU bez blokowania main thread.

Podsumowanie

  • Core Animation – niskopoziomowy framework Apple do animacji CALayer z renderowaniem na GPU
  • CALayer – podstawowa klasa z 60+ animowanymi właściwościami, obsługuje CAShapeLayer, CAGradientLayer, CATextLayer
  • CABasicAnimation – animacja jednej właściwości z fromValue/toValue, dodawana przez layer.add(animation, forKey:)
  • CATransaction – grupowanie animacji ze wspólnymi duration, timingFunction, completionBlock
  • Implicit animation – automatyczna animacja przy zmianie właściwości CALayer (czas trwania 0,25 s)
  • Presentation layer – bieżący stan warstwy podczas animacji, używany do odczytu wartości pośrednich
  • Wydajność – do 120 FPS na ProMotion, do 1000 warstw przy 60 FPS, 4 bajty/piksel

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również