Core Animation: основи, CALayer и анимация в iOS

Автор: IT Sectr Публикувано: 2026-03-01 Време за четене: 8 мин

Core Animation е нисконивов фреймуърк за анимация на Apple, работещ на ниво CALayer и осигуряващ визуализация на съдържание на GPU. Core Animation е основата на всички анимации в iOS и macOS: UIKit, AppKit, SceneKit и SpriteKit са изградени върху него. Статията обяснява архитектурата на CALayer, CABasicAnimation, CATransaction и практическите техники.

Основни точки

  • CALayer основният клас на Core Animation за управление на показването на съдържание на GPU
  • CABasicAnimation проста анимация на едно свойство на CALayer от fromValue до toValue
  • CATransaction групиране на анимации в една транзакция с общи duration и completion
  • CAAnimation абстрактен базов клас, от който наследяват CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup
  • Render server отделен процес (backboardd), интерполиращ кадри на анимация на GPU

Какво е Core Animation?

Core Animation е графичен фреймуърк на Apple, появил се в Mac OS X 10.5 Leopard (2007) и пренесен на iOS от първата версия на iPhone OS (2007). Core Animation управлява композицията, анимацията и визуализацията на слоеве (CALayer) на GPU. Всеки UIView в iOS има вграден CALayer (view.layer), чрез който се осъществява цялата визуализация.

Core Animation работи на принципа на implicit animation: някои промени на свойствата на CALayer се анимират автоматично (анимира CABasicAnimation за position, bounds, opacity, backgroundColor). Implicit-анимациите използват CATransaction по подразбиране с продължителност 0.25 секунди и крива easeInOut.

Според данни на Apple WWDC 2024, Core Animation обработва до 120 FPS на устройства с ProMotion, използвайки Metal за GPU визуализация. Размерът на типичен слой в паметта е 4 байта на пиксел (RGBA) + overhead ~100 байта на слой. Препоръчват се не повече от 1000 слоя на екран за стабилни 60 FPS.

Архитектура на CALayer

CALayer основата на Core Animation. Всеки CALayer съдържа bitmap съдържание (или препратка към GPU текстура) и дефинира геометрия (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). Слоят не обработва събития на допир за това отговаря UIView/UIScrollView. Слоевете образуват йерархия (layer tree), отразяваща йерархията на изгледите.

Core Animation поддържа три дървета от слоеве: model layer tree (действителни свойства), presentation layer tree (текущо показване по време на анимация) и render tree (данни за GPU). Presentation layer се използва за четене на междинни стойности на анимация в реално време.

Типове CALayer

CALayer има специализирани подкласове: CAShapeLayer (векторна графика), CAGradientLayer (градиент), CATextLayer (текст), CATiledLayer (големи изображения, разделени на плочки), CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer е най-популярен за персонализирана анимация благодарение на поддръжката на CGPath и анимация на strokeStart/strokeEnd.

CABasicAnimation основна анимация на свойства

CABasicAnimation е подклас на CAAnimation, анимиращ едно свойство на CALayer от начална стойност (fromValue) до крайна стойност (toValue) или относителна промяна (byValue). Анимацията се добавя към слоя чрез метода layer.add(animation, forKey:) и се изпълнява в render server без участие на приложението на всеки кадър.

Ключът (keyPath) е низ, указващ свойството: opacity, position, bounds, transform.rotation.z, cornerRadius, shadowOpacity и т.н. Core Animation поддържа 60+ анимируеми keyPath. За персонализирани свойства се използват CATransaction и presentation layer.

swift
import QuartzCore

// CABasicAnimation за opacity и 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. Анимация на прозрачност
    let fadeAnim = CABasicAnimation(keyPath: "opacity")
    fadeAnim.fromValue = 1.0
    fadeAnim.toValue = 0.2
    fadeAnim.duration = 2.0
    fadeAnim.autoreverses = true
    fadeAnim.repeatCount = .infinity

    // 2. Анимация на заобляне на ъгли
    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")
}

// Анимация на position с 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 // актуализираме model layer
}

Важно: CABasicAnimation е временно показване (presentation layer). След приключване на анимацията слоят се връща към първоначалните стойности на model layer. За фиксиране на крайното състояние задайте isRemovedOnCompletion = false, fillMode = .forwards и актуализирайте model layer до крайните стойности.

CATransaction групиране на анимации

CATransaction е механизъм за групиране на Core Animation анимации в една транзакция. CATransaction.begin() и CATransaction.commit() определят границите на транзакцията. Вътре в транзакцията могат да бъдат зададени общи параметри: duration, timingFunction, completionBlock, disableActions. CATransaction е основата на implicit-анимациите на CALayer.

Implicit animation работи, когато свойство на CALayer се променя извън анимационния блок: layer.opacity = 0.5. Core Animation автоматично създава CABasicAnimation с duration от текущия CATransaction (по подразбиране 0.25 сек). За изключване на implicit-анимация използвайте CATransaction.setDisableActions(true).

swift
// CATransaction групиране и завършване
func groupedAnimation() {
    CATransaction.begin()
    CATransaction.setAnimationDuration(1.5)
    CATransaction.setAnimationTimingFunction(
        CAMediaTimingFunction(name: .easeOut)
    )
    CATransaction.setCompletionBlock {
        print("All animations completed")
    }

    // Всички промени вътре в транзакцията се анимират с duration 1.5
    layer1.opacity = 0.3
    layer2.position = CGPoint(x: 200, y: 300)
    layer3.backgroundColor = UIColor.systemRed.cgColor

    CATransaction.commit()
}

// Изключване на implicit-анимация
func updateWithoutAnimation() {
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    layer.frame = newFrame // без анимация
    CATransaction.commit()
}

// Анимация на свойствата на 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()
}

Примери за код в Swift

Core Animation се интегрира с UIKit чрез слоя UIView. Примерът по-долу демонстрира анимация на CAShapeLayer кръгова лента за напредък с анимация на дължината на дъгата и въртене на слоя чрез 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 анимира свойството strokeEnd от 0 до 1, създавайки ефект на „пълнене" на кръговата лента за напредък. CATransaction с продължителност 0.6 и easeOut прави анимацията плавна. layer.lineCap = .round добавя заоблени краища на линията за по-спретнат вид.

Често задавани въпроси

Каква е разликата между Core Animation и UIView.animate?

Core Animation работи на ниво CALayer и се управлява чрез CABasicAnimation, CATransaction. UIView.animate е високо ниво обвивка над Core Animation, която автоматично създава CABasicAnimation за свойствата на UIView. Core Animation дава повече контрол: keyPath, timingFunction, fillMode, групиране чрез CATransaction.

Какво е implicit animation в Core Animation?

Implicit animation е автоматична анимация при промяна на анимируемо свойство на CALayer извън анимационния блок. Например layer.opacity = 0.5 създава CABasicAnimation с продължителност 0.25 сек. Implicit-анимациите се управляват чрез CATransaction и се изключват чрез setDisableActions(true).

Как да анимираме персонализирано свойство на CALayer?

За персонализирани свойства имплементирайте action(forKey:) в CALayer и върнете CAAnimation. Или използвайте CALayer.display() за ръчна визуализация с анимация чрез CADisplayLink. За свойства, поддържащи CABasicAnimation, достатъчно е да посочите keyPath като низ.

Защо CALayer е по-ефективен от UIView за анимация?

CALayer е по-лек от UIView: няма обработчици на събития (touches, жестове), не участва в Auto Layout и не поддържа accessibility. Типичен CALayer заема ~100 байта срещу ~300+ за UIView. Core Animation обработва слоевете в render server на GPU без блокиране на main thread.

Резюме

  • Core Animation нисконивов фреймуърк на Apple за анимация на CALayer с визуализация на GPU
  • CALayer основен клас с 60+ анимируеми свойства, поддържа CAShapeLayer, CAGradientLayer, CATextLayer
  • CABasicAnimation анимация на едно свойство с fromValue/toValue, добавя се чрез layer.add(animation, forKey:)
  • CATransaction групиране на анимации с общи duration, timingFunction, completionBlock
  • Implicit animation автоматична анимация при промяна на свойства на CALayer (продължителност 0.25 сек)
  • Presentation layer текущо състояние на слоя по време на анимация, използва се за четене на междинни стойности
  • Производителност до 120 FPS на ProMotion, до 1000 слоя при 60 FPS, 4 байта/пиксел

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също