CAAnimation — абстрактный базовый класс Core Animation, определяющий общий интерфейс для всех типов анимаций: CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup, CATransition. Статья объясняет иерархию классов, ключевые свойства, группировку анимаций и практические примеры на Swift.
Главное
CAAnimation — абстрактный класс Core Animation, определяющий общий интерфейс для всех анимаций. Он реализует протокол CAMediaTiming (время, повтор, автоповорот) и CAMediaTimingFillMode (поведение до/после анимации). CAAnimation нельзя инстанциировать напрямую — используйте один из подклассов: CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup, CATransition или CAAnimation (через animationForKeyPath).
Каждая CAAnimation добавляется к CALayer через метод add(_:forKey:). Параметр forKey — уникальный идентификатор анимации на слое. Один и тот же keyPath может иметь только одну активную анимацию. Для замены анимации используйте removeAnimation(forKey:) перед добавлением новой.
По данным Apple, CAAnimation — это «временное» (temporary) изменение слоя. После завершения анимации presentation layer возвращается к значениям model layer, если не заданы fillMode и isRemovedOnCompletion.
Core Animation предоставляет четыре основных подкласса CAAnimation, каждый для своего сценария анимации. Понимание иерархии помогает выбрать правильный тип для задачи.
| Класс | Назначение | Ключевые особенности |
|---|---|---|
| CABasicAnimation | Анимация одного свойства от A до B | fromValue, toValue, byValue, keyPath |
| CAKeyframeAnimation | Анимация по нескольким ключевым кадрам | values, keyTimes, path, calculationMode |
| CAAnimationGroup | Группировка нескольких анимаций | animations массив, единый duration |
| CATransition | Переход между состояниями слоя | type (fade/push/moveIn/reveal), subtype, startProgress |
CABasicAnimation — самый простой и популярный подкласс. CAKeyframeAnimation используется для сложных траекторий (например, движение по кривой Безье). CAAnimationGroup запускает несколько анимаций параллельно. CATransition — готовый переход между изображениями или состояниями контента.
Протокол CAMediaTiming — фундаментальная часть CAAnimation. Он определяет базовые временные свойства: duration (продолжительность), repeatCount (количество повторений), repeatDuration (общая длительность повторов), autoreverses (возврат к началу), beginTime (время старта относительно родителя), timeOffset (смещение внутри одного цикла), speed (скорость воспроизведения).
Свойство fillMode (CAMediaTimingFillMode) определяет отображение слоя до (backwards) и после (forwards) анимации. Значения: removed (по умолчанию — возврат к model layer), forwards (остаётся в конечном состоянии), backwards (отображает начальное состояние до старта), both (совмещает оба поведения). fillMode работает только при isRemovedOnCompletion = false.
CAAnimation наследует CAMediaTiming и может быть вложена в родительскую анимацию (CAAnimationGroup). В этом случае beginTime рассчитывается относительно начала родителя, а duration ограничивается родительским. Speed = 2.0 ускоряет анимацию вдвое.
CAAnimationGroup объединяет несколько CAAnimation в одну группу. Все дочерние анимации запускаются параллельно, если не задан beginTime для каждой. Группа имеет собственный duration, который ограничивает максимальную длительность дочерних анимаций. timingFunction группы применяется как значение по умолчанию, если дочерняя анимация не задала свой.
CAKeyframeAnimation анимирует свойство по нескольким ключевым кадрам, заданным массивом values. Параметр keyTimes (массив NSNumber от 0 до 1) определяет временные метки для каждого кадра. calculationMode задаёт интерполяцию: linear, discrete (без интерполяции), paced (равномерная скорость), cubic (сплайн), cubicPaced.
import QuartzCore
// CAAnimationGroup — комбинация анимаций
func complexLayerAnimation(_ layer: CALayer) {
let fade = CABasicAnimation(keyPath: "opacity")
fade.fromValue = 1.0
fade.toValue = 0.3
let scale = CABasicAnimation(keyPath: "transform.scale")
scale.fromValue = 1.0
scale.toValue = 1.5
let rotate = CABasicAnimation(keyPath: "transform.rotation.z")
rotate.fromValue = 0
rotate.toValue = Double.pi * 2
let group = CAAnimationGroup()
group.animations = [fade, scale, rotate]
group.duration = 2.0
group.repeatCount = .infinity
group.autoreverses = true
layer.add(group, forKey: "pulse")
}
// CAKeyframeAnimation — движение по траектории
func animateAlongPath(_ layer: CALayer) {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addCurve(
to: CGPoint(x: 200, y: 300),
controlPoint1: CGPoint(x: 100, y: 0),
controlPoint2: CGPoint(x: 100, y: 300)
)
let anim = CAKeyframeAnimation(keyPath: "position")
anim.path = path.cgPath
anim.duration = 1.5
anim.calculationMode = .cubicPaced
anim.rotationMode = .auto
anim.fillMode = .forwards
anim.isRemovedOnCompletion = false
layer.add(anim, forKey: "pathAnim")
layer.position = CGPoint(x: 200, y: 300)
}
// CAKeyframeAnimation с кастомными значениями
func bounceAnimation(_ layer: CALayer) {
let bounce = CAKeyframeAnimation(keyPath: "position.y")
bounce.values = [0, -50, 0, -25, 0, -10, 0]
bounce.keyTimes = [0, 0.15, 0.3, 0.45, 0.6, 0.8, 1.0]
bounce.duration = 0.8
bounce.timingFunction = CAMediaTimingFunction(name: .easeOut)
bounce.isAdditive = true // относительно текущей позиции
layer.add(bounce, forKey: nil)
}CAAnimationGroup выполняет fade, scale и rotate параллельно с duration 2.0. CAKeyframeAnimation с path и calculationMode = .cubicPaced обеспечивает равномерное движение вдоль кривой Безье с автоматическим поворотом (rotationMode = .auto). bounceAnimation использует isAdditive для относительного смещения.
Полный пример CAAnimation для комплексной анимации слоя с использованием CATransition для смены контента и CAAnimationGroup для пульсации.
import UIKit
import QuartzCore
class AnimationDemoView: UIView {
private let demoLayer = CALayer()
private var currentColor: CGColor = UIColor.systemBlue.cgColor
override func layoutSubviews() {
super.layoutSubviews()
demoLayer.frame = CGRect(x: bounds.midX - 40, y: bounds.midY - 40,
width: 80, height: 80)
demoLayer.backgroundColor = currentColor
demoLayer.cornerRadius = 12
layer.addSublayer(demoLayer)
}
func animateTransition() {
// CATransition — переход между состояниями
let transition = CATransition()
transition.type = .fade
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
demoLayer.add(transition, forKey: nil)
// Меняем контент через транзакцию
currentColor = currentColor == UIColor.systemBlue.cgColor
? UIColor.systemRed.cgColor
: UIColor.systemBlue.cgColor
demoLayer.backgroundColor = currentColor
}
func startPulse() {
let scaleUp = CABasicAnimation(keyPath: "transform.scale")
scaleUp.fromValue = 1.0
scaleUp.toValue = 1.3
let fadeOut = CABasicAnimation(keyPath: "opacity")
fadeOut.fromValue = 1.0
fadeOut.toValue = 0.6
let glow = CABasicAnimation(keyPath: "shadowOpacity")
glow.fromValue = 0.0
glow.toValue = 0.8
let group = CAAnimationGroup()
group.animations = [scaleUp, fadeOut, glow]
group.duration = 1.2
group.autoreverses = true
group.repeatCount = .infinity
group.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
demoLayer.add(group, forKey: "pulse")
}
func stopAnimations() {
demoLayer.removeAllAnimations()
demoLayer.transform = CATransform3DIdentity
demoLayer.opacity = 1.0
demoLayer.shadowOpacity = 0.0
}
}CATransition с type: .fade создаёт плавный переход между двумя состояниями backgroundColor. CAAnimationGroup объединяет scale, opacity и shadowOpacity для эффекта пульсации. removeAllAnimations() сбрасывает все анимации и возвращает слой к исходным значениям model layer.
Часто задаваемые вопросы
CABasicAnimation анимирует свойство от начального (fromValue) до конечного (toValue) значения с равномерной интерполяцией. CAKeyframeAnimation позволяет задать массив промежуточных значений (values) и временных меток (keyTimes) для нелинейной анимации по ключевым кадрам, включая движение по кривой через path.
CAAnimationGroup нужен, когда несколько анимаций должны выполняться параллельно с гарантией синхронизации: групповой duration ограничивает все дочерние анимации. Используйте group для комбинированных эффектов: масштабирование + изменение прозрачности + вращение одновременно.
fillMode определяет отображение слоя до (backwards) и после (forwards) анимации. Значение .forwards оставляет слой в конечном состоянии после завершения анимации (требует isRemovedOnCompletion = false). .both комбинирует backwards (начальное состояние до старта) и forwards.
CAAnimation — это объект анимации (инструкция), который добавляется к CALayer через layer.add(animation, forKey:). Анимация существует как отдельный объект, может быть переиспользована (с копированием) и управляется через CAMediaTiming. Слой может иметь множество анимаций с разными ключами.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также