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). Неявні анімації використовують CATransaction за замовчуванням з тривалістю 0,25 секунди та кривою easeInOut.

За даними Apple WWDC 2024, Core Animation обробляє до 120 FPS на пристроях з ProMotion, використовуючи Metal для GPU-рендерингу. Розмір типового шару в пам'яті — 4 байти на піксель (RGBA) + накладні витрати ~100 байт на шар. Рекомендується не більше 1000 шарів на екрані для стабільних 60 FPS.

Архітектура CALayer

CALayer — основа Core Animation. Кожен CALayer містить bitmap-контент (або посилання на GPU-текстуру) та визначає геометрію (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). Шари не обробляють події дотиків — за це відповідає UIView/UIScrollView. Шари утворюють ієрархію (layer tree), що дзеркально відображає view hierarchy.

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 — основа неявних анімацій CALayer.

Неявна анімація спрацьовує, коли властивість CALayer змінюється поза анімаційним блоком: layer.opacity = 0.5. Core Animation автоматично створює CABasicAnimation з duration з поточного CATransaction (за замовчуванням 0,25 с). Для вимкнення неявної анімації використовуйте 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()
}

// Вимкнення неявної анімації
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 з duration 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.

Що таке неявна анімація в Core Animation?

Implicit animation — автоматична анімація при зміні анімованої властивості CALayer поза блоком анімації. Наприклад, layer.opacity = 0.5 створює CABasicAnimation з duration 0,25 с. Неявні анімації керуються через CATransaction та вимикаються через setDisableActions(true).

Як анімувати кастомну властивість CALayer?

Для кастомних властивостей реалізуйте action(forKey:) в CALayer та поверніть CAAnimation. Або використовуйте CALayer.display() для ручного рендерингу з анімацією через CADisplayLink. Для властивостей, що підтримують CABasicAnimation, достатньо вказати keyPath у вигляді рядка.

Чому CALayer ефективніший за UIView для анімації?

CALayer легший за UIView: не має обробників подій (touches, gestures), не бере участі в Auto Layout та не підтримує accessibility. Типовий CALayer займає ~100 байт проти ~300+ у UIView. Core Animation обробляє шари в render server на GPU без блокування головного потоку.

Підсумки

  • 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також