Category: Apple SDKs

  • A Beginner’s Guide to Core Animation in iOS

    A Beginner’s Guide to Core Animation in iOS

    Core Animation might seem intimidating for new iOS developers, but it’s essential to understand how animations work under the hood. While UIKit (and SwiftUI) provide high-level APIs for animations, Core Animation (CA) is the underlying system responsible for the motion you see.

    Understanding Core Animation

    Core Animation manages the visual content of your app using CALayer objects. Every UIView has an associated CALayer that you can manipulate directly if you need more fine-grained control than UIKit’s higher-level animation APIs. This is helpful when you need effects that aren’t possible through property-based animators or standard view transitions.

    Under the hood, Core Animation uses two models:

    • The model layer: Reflects the “real” values of the view’s properties (position, size, corner radius, etc.).
    • The presentation layer: Reflects the current onscreen values during an active animation. When the animation completes, you usually update the model layer to match the final animated state.

    1. Moving a View

    Below is a basic Swift example showing how to move the image from one position to another using Core Animation:

    class ViewController: UIViewController {
        
        let duck = UIImageView(image: UIImage(named: "duck"))
        
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = UIColor(named: "orange")
            
            view.addSubview(duck)
            animateLeftToRight()
        }
        
        private func animateLeftToRight() {
            let animation = CABasicAnimation()
            animation.keyPath = "position.x"
            animation.fromValue = 20 + 140/2
            animation.toValue = 300
            animation.duration = 1
            
            duck.layer.add(animation, forKey: "move")
            
            // defines the final position so it doesn't reset
            duck.layer.position = CGPoint(x: 300, y: 100 + 100/2)
        }
    }

    You can get the source code of this project here

    When you remove the line that sets redView.layer.position.x = 300, the square will slide then “snap back” to its original position because the model layer wasn’t updated with the animation’s final value.

    2. Scaling a View

    Need to grow or shrink a view? You can animate the scale using the "transform.scale" keyPath:

    private func animateScale() {
        let animation = CABasicAnimation()
        animation.keyPath = "transform.scale"
        animation.fromValue = 1
        animation.toValue = 2
        animation.duration = 2
        
        duck.layer.add(animation, forKey: "scale")
        
        // defines the final scale
        duck.layer.transform = CATransform3DMakeScale(2, 2, 1)
    }

    3. Rotation

    Rotating a view about its Z-axis is similar, except you use "transform.rotation.z":

    private func animateRotation() {
        let animation = CABasicAnimation()
        animation.keyPath = "transform.rotation.z" // z-axis
        animation.fromValue = 0
        animation.toValue = CGFloat.pi / 4 //45 degress in radians
        animation.duration = 2
        
        duck.layer.add(animation, forKey: "rotate")
        duck.layer.transform = CATransform3DMakeRotation(CGFloat.pi / 2, 0, 0, 1)
    }

    Here, "transform.rotation.z" indicates rotation about the Z-axis (the axis “coming out of the screen”).

    4. Keyframe Animations (Shake Effect)

    Keyframe animations let you define multiple points in time, making it easy to create effects like “shaking” a login form when the user enters invalid credentials:

    private func animateShakeTextField() {
          let animation = CAKeyframeAnimation()
          animation.keyPath = "position.x"
          animation.values = [0, 10, -10, 10, 0]
          animation.keyTimes = [0, 0.16, 0.5, 0.83, 1]
          animation.duration = 0.4
          
          animation.isAdditive = true
          duck.layer.add(animation, forKey: "shake")
    }

    You can apply this same approach to any view—just change "position.x" to "position.y" or another property as needed.

    Tips for Using Core Animation

    1. Update the Model Layer
      Always remember to set the final position or transform on the view’s model layer if you want its new state to persist after the animation finishes.
    2. Anchor Point Gotchas
      The default anchor point is the view’s center. If you change your view’s anchor point, your animations might shift unpredictably if you don’t adjust positions accordingly.
    3. Coordinate System
      Core Animation uses a coordinate system that starts at the top-left corner, increasing down and to the right. For position-based animations, ensure you calculate the correct center points (especially if you set frames or anchor points manually).
    4. Combine with UIKit
      You can mix these animations with standard UIKit property animators. This is sometimes easier for simpler transitions, but dropping down to Core Animation’s layer-based approach gives you maximum power.
    5. Experiment in Small Steps
      Because it’s easy to get lost in the details of the model/presentation layer, test small animations first. Even drawing a shape or path to see if it lines up with what you expect can make debugging much easier.

    Conclusion

    Core Animation unlocks a wealth of possibilities beyond UIKit or SwiftUI’s higher-level animations. By understanding how CALayer, keyPaths, and the model/presentation layers work, you can combine transforms, positions, and keyframe animations to produce delightful user experiences.