Core Animation: Basics, CALayer and Animation in iOS

Author: IT Sectr Published: 2026-03-01 Reading time: 8 min

Core Animation is Apple’s low-level animation framework that operates at the CALayer level and renders content on the GPU. Core Animation is the foundation of all animations in iOS and macOS: UIKit, AppKit, SceneKit, and SpriteKit are built on top of it. This article explains the architecture of CALayer, CABasicAnimation, CATransaction, and practical techniques.

Key Takeaways

  • CALayer — the base class of Core Animation for managing content display on the GPU
  • CABasicAnimation — a simple animation of one CALayer property from fromValue to toValue
  • CATransaction — grouping animations into a single transaction with shared duration and completion
  • CAAnimation — an abstract base class from which CABasicAnimation, CAKeyframeAnimation, and CAAnimationGroup inherit
  • Render server — a separate process (backboardd) that interpolates animation frames on the GPU

What is Core Animation?

Core Animation is Apple’s graphics framework introduced in Mac OS X 10.5 Leopard (2007) and ported to iOS with the first version of iPhone OS (2007). Core Animation manages composition, animation, and rendering of layers (CALayer) on the GPU. Every UIView in iOS has a built-in CALayer (view.layer) through which all drawing occurs.

Core Animation operates on the principle of implicit animation: some CALayer property changes animate automatically (CABasicAnimation for position, bounds, opacity, backgroundColor). Implicit animations use CATransaction by default with a duration of 0.25 seconds and an easeInOut curve.

According to Apple WWDC 2024, Core Animation processes up to 120 FPS on ProMotion devices, using Metal for GPU rendering. A typical layer’s memory footprint is 4 bytes per pixel (RGBA) + ~100 bytes overhead per layer. It is recommended to have no more than 1000 layers on screen for stable 60 FPS.

CALayer Architecture

CALayer is the foundation of Core Animation. Each CALayer contains bitmap content (or a GPU texture reference) and defines geometry (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow). Layers do not handle touch events — UIView/UIScrollView handle that. Layers form a hierarchy (layer tree) that mirrors the view hierarchy.

Core Animation maintains three layer trees: the model layer tree (actual properties), the presentation layer tree (current display during animation), and the render tree (GPU data). The presentation layer is used to read real-time intermediate animation values.

CALayer Types

CALayer has specialized subclasses: CAShapeLayer (vector graphics), CAGradientLayer (gradient), CATextLayer (text), CATiledLayer (large images split into tiles), CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer is the most popular for custom animation thanks to CGPath support and strokeStart/strokeEnd animation.

CABasicAnimation — Basic Property Animation

CABasicAnimation is a subclass of CAAnimation that animates a single CALayer property from a starting value (fromValue) to an ending value (toValue) or by a relative change (byValue). The animation is added to the layer via layer.add(animation, forKey:) and runs in the render server without app involvement on each frame.

The key (keyPath) is a string specifying the property: opacity, position, bounds, transform.rotation.z, cornerRadius, shadowOpacity, etc. Core Animation supports 60+ animatable keyPaths. For custom properties, CATransaction and the presentation layer are used.

swift
import QuartzCore

// CABasicAnimation for opacity and 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. Opacity animation
    let fadeAnim = CABasicAnimation(keyPath: "opacity")
    fadeAnim.fromValue = 1.0
    fadeAnim.toValue = 0.2
    fadeAnim.duration = 2.0
    fadeAnim.autoreverses = true
    fadeAnim.repeatCount = .infinity

    // 2. Corner radius animation
    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 animation with 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 // updating model layer
}

Important: CABasicAnimation is a temporary display (presentation layer). After the animation completes, the layer returns to its model layer values. To freeze the final state, set isRemovedOnCompletion = false, fillMode = .forwards, and update the model layer to the final values.

CATransaction — Grouping Animations

CATransaction is a mechanism for grouping Core Animation animations into a single transaction. CATransaction.begin() and CATransaction.commit() define the transaction boundaries. Inside a transaction, shared parameters can be set: duration, timingFunction, completionBlock, disableActions. CATransaction is the foundation of CALayer implicit animations.

Implicit animation occurs when a CALayer property changes outside an animation block: layer.opacity = 0.5. Core Animation automatically creates a CABasicAnimation with the duration from the current CATransaction (default 0.25 s). To disable implicit animation, use CATransaction.setDisableActions(true).

swift
// CATransaction — grouping and completion
func groupedAnimation() {
    CATransaction.begin()
    CATransaction.setAnimationDuration(1.5)
    CATransaction.setAnimationTimingFunction(
        CAMediaTimingFunction(name: .easeOut)
    )
    CATransaction.setCompletionBlock {
        print("All animations completed")
    }

    // All changes within the transaction are animated with duration 1.5
    layer1.opacity = 0.3
    layer2.position = CGPoint(x: 200, y: 300)
    layer3.backgroundColor = UIColor.systemRed.cgColor

    CATransaction.commit()
}

// Disabling implicit animation
func updateWithoutAnimation() {
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    layer.frame = newFrame // without animation
    CATransaction.commit()
}

// Animating CAShapeLayer properties
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 Code Examples

Core Animation integrates with UIKit through the UIView layer. The example below demonstrates CAShapeLayer animation — a circular progress with arc length animation and layer rotation via 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 animates the strokeEnd property from 0 to 1, creating a circular progress “fill” effect. CATransaction with duration 0.6 and easeOut makes the animation smooth. layer.lineCap = .round adds rounded line ends for a cleaner visual.

Frequently Asked Questions

What is the difference between Core Animation and UIView.animate?

Core Animation works at the CALayer level and is controlled via CABasicAnimation and CATransaction. UIView.animate is a high-level wrapper around Core Animation that automatically creates CABasicAnimation for UIView properties. Core Animation provides more control: keyPath, timingFunction, fillMode, grouping via CATransaction.

What is implicit animation in Core Animation?

Implicit animation is automatic animation that occurs when an animatable CALayer property is changed outside an animation block. For example, layer.opacity = 0.5 creates a CABasicAnimation with 0.25 s duration. Implicit animations are managed via CATransaction and can be disabled using setDisableActions(true).

How to animate a custom CALayer property?

For custom properties, implement action(forKey:) in CALayer and return a CAAnimation. Alternatively, use CALayer.display() for manual drawing with animation via CADisplayLink. For properties that support CABasicAnimation, simply specify the keyPath as a string.

Why is CALayer more efficient than UIView for animation?

CALayer is lighter than UIView: it has no event handlers (touches, gestures), does not participate in Auto Layout, and does not support accessibility. A typical CALayer takes ~100 bytes compared to ~300+ for UIView. Core Animation processes layers in the render server on the GPU without blocking the main thread.

Summary

  • Core Animation — Apple’s low-level framework for CALayer animation with GPU rendering
  • CALayer — base class with 60+ animatable properties, supports CAShapeLayer, CAGradientLayer, CATextLayer
  • CABasicAnimation — single-property animation with fromValue/toValue, added via layer.add(animation, forKey:)
  • CATransaction — grouping animations with shared duration, timingFunction, completionBlock
  • Implicit animation — automatic animation when CALayer properties change (duration 0.25 s)
  • Presentation layer — current layer state during animation, used to read intermediate values
  • Performance — up to 120 FPS on ProMotion, up to 1000 layers at 60 FPS, 4 bytes/pixel

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also