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 анимируются автоматически (animateCABasicAnimation для position, bounds, opacity, backgroundColor). Implicit-анимации используют CATransaction по умолчанию с duration 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). Layer не обрабатывает события касаний — за это отвечает 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 — это temporary-отображение (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 — группировка и completion
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 с 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.

Что такое implicit animation в Core Animation?

Implicit animation — автоматическая анимация при изменении анимируемого свойства CALayer вне блока анимации. Например, layer.opacity = 0.5 создаёт CABasicAnimation с duration 0.25 с. Implicit-анимации управляются через 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 без блокировки 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 (duration 0.25 с)
  • Presentation layer — текущее состояние слоя во время анимации, используется для чтения промежуточных значений
  • Производительность — до 120 FPS на ProMotion, до 1000 слоёв при 60 FPS, 4 байта/пиксель

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

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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