Core Animation é o framework de animação de baixo nível da Apple que opera no nível de CALayer e renderiza conteúdo na GPU. Core Animation é a base de todas as animações em iOS e macOS: UIKit, AppKit, SceneKit e SpriteKit são construídos sobre ele. Este artigo explica a arquitetura do CALayer, CABasicAnimation, CATransaction e técnicas práticas.
Pontos principais
Core Animation é o framework gráfico da Apple introduzido no Mac OS X 10.5 Leopard (2007) e portado para iOS com a primeira versão do iPhone OS (2007). O Core Animation gerencia a composição, animação e renderização de camadas (CALayer) na GPU. Cada UIView no iOS tem um CALayer embutido (view.layer) através do qual todo o desenho ocorre.
O Core Animation opera no princípio de animação implícita: algumas alterações de propriedades do CALayer animam automaticamente (CABasicAnimation para position, bounds, opacity, backgroundColor). As animações implícitas usam CATransaction por padrão com duração de 0,25 segundos e curva easeInOut.
De acordo com a Apple WWDC 2024, o Core Animation processa até 120 FPS em dispositivos ProMotion, usando Metal para renderização em GPU. O consumo de memória de uma camada típica é de 4 bytes por pixel (RGBA) + ~100 bytes de overhead por camada. Recomenda-se não mais de 1000 camadas na tela para 60 FPS estáveis.
CALayer é a base do Core Animation. Cada CALayer contém conteúdo bitmap (ou referência de textura GPU) e define a geometria (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). As camadas não lidam com eventos de toque — UIView/UIScrollView cuidam disso. As camadas formam uma hierarquia (layer tree) que espelha a hierarquia de views.
O Core Animation mantém três árvores de camadas: a model layer tree (propriedades reais), a presentation layer tree (exibição atual durante a animação) e a render tree (dados da GPU). A camada de apresentação é usada para ler valores intermediários de animação em tempo real.
CALayer possui subclasses especializadas: CAShapeLayer (gráficos vetoriais), CAGradientLayer (gradiente), CATextLayer (texto), CATiledLayer (imagens grandes divididas em tiles), CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer é o mais popular para animação personalizada graças ao suporte a CGPath e animação strokeStart/strokeEnd.
CABasicAnimation é uma subclasse de CAAnimation que anima uma única propriedade do CALayer de um valor inicial (fromValue) até um valor final (toValue) ou por uma alteração relativa (byValue). A animação é adicionada à camada através de layer.add(animation, forKey:) e executada no render server sem envolvimento do aplicativo em cada quadro.
A chave (keyPath) é uma string que especifica a propriedade: opacity, position, bounds, transform.rotation.z, cornerRadius, shadowOpacity, etc. O Core Animation suporta mais de 60 keyPaths animáveis. Para propriedades personalizadas, são usados CATransaction e a camada de apresentação.
import QuartzCore
// CABasicAnimation para opacity e 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. Animação de opacidade
let fadeAnim = CABasicAnimation(keyPath: "opacity")
fadeAnim.fromValue = 1.0
fadeAnim.toValue = 0.2
fadeAnim.duration = 2.0
fadeAnim.autoreverses = true
fadeAnim.repeatCount = .infinity
// 2. Animação de raio de canto
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")
}
// Animação de position com 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 // atualizando model layer
}Importante: CABasicAnimation é uma exibição temporária (presentation layer). Após a animação ser concluída, a camada retorna aos seus valores do model layer. Para congelar o estado final, defina isRemovedOnCompletion = false, fillMode = .forwards e atualize o model layer para os valores finais.
CATransaction é um mecanismo para agrupar animações do Core Animation em uma única transação. CATransaction.begin() e CATransaction.commit() definem os limites da transação. Dentro de uma transação, parâmetros compartilhados podem ser definidos: duration, timingFunction, completionBlock, disableActions. CATransaction é a base das animações implícitas do CALayer.
A animação implícita ocorre quando uma propriedade do CALayer é alterada fora de um bloco de animação: layer.opacity = 0,5. O Core Animation cria automaticamente uma CABasicAnimation com a duração do CATransaction atual (padrão 0,25 s). Para desativar a animação implícita, use CATransaction.setDisableActions(true).
// CATransaction — agrupamento e conclusão
func groupedAnimation() {
CATransaction.begin()
CATransaction.setAnimationDuration(1.5)
CATransaction.setAnimationTimingFunction(
CAMediaTimingFunction(name: .easeOut)
)
CATransaction.setCompletionBlock {
print("All animations completed")
}
// Todas as alterações dentro da transação são animadas com duração 1.5
layer1.opacity = 0.3
layer2.position = CGPoint(x: 200, y: 300)
layer3.backgroundColor = UIColor.systemRed.cgColor
CATransaction.commit()
}
// Desativando animação implícita
func updateWithoutAnimation() {
CATransaction.begin()
CATransaction.setDisableActions(true)
layer.frame = newFrame // sem animação
CATransaction.commit()
}
// Animando propriedades do 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()
}O Core Animation integra-se com UIKit através da camada UIView. O exemplo abaixo demonstra a animação CAShapeLayer — um progresso circular com animação de comprimento de arco e rotação da camada via 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 anima a propriedade strokeEnd de 0 a 1, criando um efeito de “preenchimento” de progresso circular. CATransaction com duração 0,6 e easeOut torna a animação suave. layer.lineCap = .round adiciona extremidades arredondadas à linha para um visual mais limpo.
Perguntas frequentes
Core Animation funciona no nível do CALayer e é controlado através de CABasicAnimation e CATransaction. UIView.animate é um wrapper de alto nível em torno do Core Animation que cria automaticamente CABasicAnimation para propriedades UIView. O Core Animation oferece mais controle: keyPath, timingFunction, fillMode, agrupamento via CATransaction.
Animação implícita é uma animação automática que ocorre quando uma propriedade animável do CALayer é alterada fora de um bloco de animação. Por exemplo, layer.opacity = 0,5 cria uma CABasicAnimation com duração de 0,25 s. As animações implícitas são gerenciadas via CATransaction e podem ser desativadas usando setDisableActions(true).
Para propriedades personalizadas, implemente action(forKey:) no CALayer e retorne uma CAAnimation. Alternativamente, use CALayer.display() para desenho manual com animação via CADisplayLink. Para propriedades que suportam CABasicAnimation, basta especificar o keyPath como uma string.
CALayer é mais leve que UIView: não possui manipuladores de eventos (touches, gestures), não participa do Auto Layout e não suporta acessibilidade. Um CALayer típico ocupa ~100 bytes contra ~300+ do UIView. O Core Animation processa as camadas no render server na GPU sem bloquear a thread principal.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também