Core Animation је Apple-ов нисконвојски фрејмворк за анимацију који ради на нивоу CALayer и обезбеђује приказивање садржаја на GPU. Core Animation је основа свих анимација у iOS и macOS: UIKit, AppKit, SceneKit и SpriteKit су изграђени на њој. Чланак објашњава архитектуру CALayer, CABasicAnimation, CATransaction и практичне технике.
Главне тачке
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 основа Core Animation. Сваки CALayer садржи bitmap садржај (или референцу на GPU текстуру) и дефинише геометрију (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). Слој не обрађује догађаје додира за то је задужен UIView/UIScrollView. Слојеви формирају хијерархију (layer tree) која одражава view хијерархију.
Core Animation подржава три стабла слојева: model layer tree (стварна својства), presentation layer tree(тренутни приказ током анимације) и render tree (подаци за GPU). Presentation layer се користи за читање међувредности анимације у реалном времену.
CALayer има специјализоване подкласе: CAShapeLayer (векторска графика), CAGradientLayer (градијент), CATextLayer (текст), CATiledLayer (велике слике подељене на плочице), CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer је најпопуларнији за прилагођену анимацију захваљујући подршци за CGPath и анимацију strokeStart/strokeEnd.
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.
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 је механизам за груписање 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).
// 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()
}Core Animation се интегрише са UIKit кроз слој UIView. Пример испод демонстрира анимацију CAShapeLayer кружну траку напретка са анимацијом дужине лука и ротацијом слоја кроз CABasicAnimation.
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 ради на нивоу CALayer и управља се кроз CABasicAnimation, CATransaction. UIView.animate је високонивојски омотач изнад Core Animation који аутоматски креира CABasicAnimation за својства UIView. Core Animation даје више контроле: keyPath, timingFunction, fillMode, груписање кроз CATransaction.
Implicit animation је аутоматска анимација при промени анимираног својства CALayer ван блока анимације. На пример, layer.opacity = 0.5 креира CABasicAnimation са трајањем 0.25 с. Implicit-анимације се управљају кроз CATransaction и искључују кроз setDisableActions(true).
За прилагођена својства имплементирајте action(forKey:) у CALayer и вратите CAAnimation. Или користите CALayer.display() за ручно рендеровање са анимацијом кроз CADisplayLink. За својства која подржавају CABasicAnimation, довољно је навести keyPath као стринг.
CALayer је лакши од UIView: нема управљаче догађајима (touches, гестови), не учествује у Auto Layout и не подржава accessibility. Типичан CALayer заузима ~100 бајтова наспрам ~300+ за UIView. Core Animation обрађује слојеве у render server-у на GPU без блокирања main thread.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође