Core Animation: bazele, CALayer și animația în iOS

Autor: IT Sectr Publicat: 2026-03-01 Timp de citire: 8 min

Core Animation este un framework de animație de nivel scăzut al Apple, care funcționează la nivelul CALayer și asigură randarea conținutului pe GPU. Core Animation stă la baza tuturor animațiilor în iOS și macOS: UIKit, AppKit, SceneKit și SpriteKit sunt construite pe ea. Articolul explică arhitectura CALayer, CABasicAnimation, CATransaction și tehnicile practice.

Principalele puncte

  • CALayer clasa de bază Core Animation pentru gestionarea afișării conținutului pe GPU
  • CABasicAnimation animația simplă a unei proprietăți CALayer de la fromValue la toValue
  • CATransaction gruparea animațiilor într-o singură tranzacție cu duration și completion comune
  • CAAnimation clasa de bază abstractă de care moștenesc CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup
  • Render server proces separat (backboardd) care interpolează cadrele de animație pe GPU

Ce este Core Animation?

Core Animation este un framework grafic Apple care a apărut în Mac OS X 10.5 Leopard (2007) și a fost portat pe iOS de la prima versiune iPhone OS (2007). Core Animation gestionează compoziția, animația și randarea straturilor (CALayer) pe GPU. Fiecare UIView în iOS are un CALayer încorporat (view.layer) prin care are loc întreaga randare.

Core Animation funcționează pe principiul implicit animation: unele modificări ale proprietăților CALayer sunt animate automat (animează CABasicAnimation pentru position, bounds, opacity, backgroundColor). Implicit-animațiile folosesc CATransaction în mod implicit cu durata de 0.25 secunde și curba easeInOut.

Conform datelor Apple WWDC 2024, Core Animation procesează până la 120 FPS pe dispozitivele ProMotion, folosind Metal pentru randarea GPU. Dimensiunea unui strat tipic în memorie este de 4 octeți pe pixel (RGBA) + overhead ~100 de octeți per strat. Se recomandă cel mult 1000 de straturi pe ecran pentru 60 FPS stabile.

Arhitectura CALayer

CALayer baza Core Animation. Fiecare CALayer conține conținut bitmap (sau referință la o textură GPU) și definește geometria (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). Stratul nu procesează evenimente tactile de aceasta se ocupă UIView/UIScrollView. Straturile formează o ierarhie (layer tree) care oglindește ierarhia de vizualizare.

Core Animation suportă trei arbori de straturi: model layer tree (proprietăți reale), presentation layer tree (afișarea curentă în timpul animației) și render tree (date pentru GPU). Presentation layer este folosit pentru citirea valorilor intermediare ale animației în timp real.

Tipuri de CALayer

CALayer are subclase specializate: CAShapeLayer (grafică vectorială), CAGradientLayer (gradient), CATextLayer (text), CATiledLayer (imagini mari împărțite în segmente), CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer este cel mai popular pentru animații personalizate datorită suportului pentru CGPath și animația strokeStart/strokeEnd.

CABasicAnimation animația de bază a proprietăților

CABasicAnimation este o subclasă CAAnimation care animează o singură proprietate CALayer de la valoarea inițială (fromValue) la valoarea finală (toValue) sau modificarea relativă (byValue). Animația este adăugată stratului prin metoda layer.add(animation, forKey:) și este executată în render server fără participarea aplicației la fiecare cadru.

Cheia (keyPath) este un șir care indică proprietatea: opacity, position, bounds, transform.rotation.z, cornerRadius, shadowOpacity etc. Core Animation suportă 60+ de keyPath-uri animabile. Pentru proprietăți personalizate se folosesc CATransaction și presentation layer.

swift
import QuartzCore

// CABasicAnimation pentru 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. Animația transparenței
    let fadeAnim = CABasicAnimation(keyPath: "opacity")
    fadeAnim.fromValue = 1.0
    fadeAnim.toValue = 0.2
    fadeAnim.duration = 2.0
    fadeAnim.autoreverses = true
    fadeAnim.repeatCount = .infinity

    // 2. Animația rotunjirii colțurilor
    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")
}

// Animația position cu 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 // actualizăm model layer
}

Important: CABasicAnimation este o afișare temporară (presentation layer). După terminarea animației, stratul revine la valorile inițiale ale model layer. Pentru a fixa starea finală, setați isRemovedOnCompletion = false, fillMode = .forwards și actualizați model layer la valorile finale.

CATransaction gruparea animațiilor

CATransaction este un mecanism de grupare a animațiilor Core Animation într-o singură tranzacție. CATransaction.begin() și CATransaction.commit() definesc granițele tranzacției. În interiorul tranzacției pot fi setați parametri comuni: duration, timingFunction, completionBlock, disableActions. CATransaction stă la baza implicit-animațiilor CALayer.

Implicit animation funcționează atunci când proprietatea CALayer este modificată în afara blocului de animație: layer.opacity = 0.5. Core Animation creează automat CABasicAnimation cu duration din CATransaction curent (implicit 0.25 s). Pentru a dezactiva implicit-animația utilizați CATransaction.setDisableActions(true).

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

    // Toate modificările din tranzacție sunt animate cu durata 1.5
    layer1.opacity = 0.3
    layer2.position = CGPoint(x: 200, y: 300)
    layer3.backgroundColor = UIColor.systemRed.cgColor

    CATransaction.commit()
}

// Dezactivarea implicit-animației
func updateWithoutAnimation() {
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    layer.frame = newFrame // fără animație
    CATransaction.commit()
}

// Animația proprietăților 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()
}

Exemple de cod în Swift

Core Animation se integrează cu UIKit prin stratul UIView. Exemplul de mai jos demonstrează animația CAShapeLayer o bară de progres circulară cu animația lungimii arcului și rotația stratului prin 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 animează proprietatea strokeEnd de la 0 la 1, creând efectul de „umplere“ a barei de progres circulare. CATransaction cu durata 0.6 și easeOut face animația lină. layer.lineCap = .round adaugă capete rotunjite ale liniei pentru un aspect mai îngrijit.

Întrebări frecvente

Care este diferența dintre Core Animation și UIView.animate?

Core Animation funcționează la nivelul CALayer și este gestionată prin CABasicAnimation, CATransaction. UIView.animate este un înveliș de nivel înalt peste Core Animation care creează automat CABasicAnimation pentru proprietățile UIView. Core Animation oferă mai mult control: keyPath, timingFunction, fillMode, gruparea prin CATransaction.

Ce este implicit animation în Core Animation?

Implicit animation este animația automată la modificarea proprietății animabile CALayer în afara blocului de animație. De exemplu, layer.opacity = 0.5 creează CABasicAnimation cu durata 0.25 s. Implicit-animațiile sunt gestionate prin CATransaction și dezactivate prin setDisableActions(true).

Cum să animezi o proprietate personalizată CALayer?

Pentru proprietăți personalizate implementați action(forKey:) în CALayer și returnați CAAnimation. Sau folosiți CALayer.display() pentru randare manuală cu animație prin CADisplayLink. Pentru proprietăți care suportă CABasicAnimation, este suficient să specificați keyPath ca șir de caractere.

De ce CALayer este mai eficient decât UIView pentru animație?

CALayer este mai ușor decât UIView: nu are gestionari de evenimente (touches, gesturi), nu participă la Auto Layout și nu suportă accessibility. Un CALayer tipic ocupă ~100 de octeți față de ~300+ pentru UIView. Core Animation procesează straturile în render server pe GPU fără a bloca main thread.

Concluzii

  • Core Animation framework de nivel scăzut Apple pentru animația CALayer cu randare pe GPU
  • CALayer clasa de bază cu 60+ proprietăți animabile, suportă CAShapeLayer, CAGradientLayer, CATextLayer
  • CABasicAnimation animația unei proprietăți cu fromValue/toValue, adăugată prin layer.add(animation, forKey:)
  • CATransaction gruparea animațiilor cu duration, timingFunction, completionBlock comune
  • Implicit animation animație automată la modificarea proprietăților CALayer (durata 0.25 s)
  • Presentation layer starea curentă a stratului în timpul animației, folosită pentru citirea valorilor intermediare
  • Performanță până la 120 FPS pe ProMotion, până la 1000 de straturi la 60 FPS, 4 octeți/pixel

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și