Mastering SwiftUI Animations: Phase Animations

Author Image

Mazen Kourouche

Jun 12, 2023

Phase Animations in SwiftUI

Explore the world of SwiftUI's phase-based animations in our latest post. Learn through custom examples and take your iOS animation skills up a notch!


With SwiftUI's recent advances, animation has become incredibly accessible for iOS developers. One of the latest additions is the phase-based animation, which is designed to animate discrete steps within an animation.

This article aims to explore phase-based animations, illustrating the process with custom examples. Let's dive in!

What is a Phase Animation?

Phase animations are SwiftUI's way of creating sequences of animations that cycle through predefined states or phases. With each phase representing a discrete step in an animation, you can create highly customisable animations with ease.

Using PhaseAnimator

SwiftUI's new PhaseAnimator is the hero of the show here. It enables developers to animate their content by cycling through a collection of phases. The basic structure of PhaseAnimator is as follows:

PhaseAnimator(some Sequence<Phase>, content: (Phase) -> Content, animation: (Phase) -> Animation?)

In this block, you define a sequence of phases for the animation. Then, you use these phases within your content view builder closure to apply specific animations.

PhaseAnimator in Action

Let's illustrate phase animations with a simple example: a colour changing square, which becomes a circle as it animates.

First, let's create our Phase enum with each phase in our animation:

enum Phase: CaseIterable {
    case initial
    case unroundCorners
    case rotate
    case finish
}

Next, let's we’ll add computed properties for each attribute we’ll be animating. For this animation, we’ll be animating the corner radius, colour and rotation:

enum Phase: CaseIterable {
    case initial
    case unroundCorners
    case rotate
    case finish

    var cornerRadius: Double {
        switch self {
        case .initial, .finish: 50
        case .unroundCorners, .rotate: 0
        }
    }

    var rotation: Angle {
        switch self {
        case .initial, .unroundCorners: .degrees(0)
        case .rotate, .finish: .degrees(180)
        }
    }

    var foregroundColor: Color {
        switch self {
        case .initial, .unroundCorners, .finish: .purple
        case .rotate: .blue
        }
    }
}
Corner radius: starts and finishes at 50 (half the width of our view - we’ll be setting it to 100) to create a circle, and 0 in between for our square.
Rotation: starts at 0, begins rotating after it morphs into a square, rotates, then rotates back after the animation ends.
Foreground colour: starts as purple, begins changing colour to blue after it morphs into a square, rotates, then changes back to purple.

Next, let's create our MorphShapeView. We’ll start with a basic rectangle.

struct MorphShapeView: View {
    let size = 100.0
    var body: some View {
        Rectangle()
            .frame(width: size, height: size)
    }
}

Now for the fun! We’ll use the PhaseAnimator with our MorphShapeView to create the animation:

struct MorphShapeView: View {
    let size = 100.0
    var body: some View {
        Rectangle()
            .frame(width: size, height: size)
						.phaseAnimator(
               Phase.allCases
            ) { content, phase in
                content
                /* Add modifiers based on phase */
            } animation: { phase in
                /* Modify animation based on phase */
            }
    }
}

To create the desired animation, we'll add modifiers and adjust the animation based on the phases. Here's the updated code:

struct MorphShapeView: View {
    let size = 100.0
    var body: some View {
        Rectangle()
            .frame(width: size, height: size)
						.phaseAnimator(
               Phase.allCases
            ) { content, phase in
                content
			            .clipShape(RoundedRectangle(cornerRadius: phase.cornerRadius))
                  .foregroundStyle(phase.foregroundColor)
                  .rotationEffect(phase.rotation)
            } animation: { phase in
                switch phase {
                case .initial, .unroundCorners:
                    return .spring(duration: 0.3)
                case .rotate: return .spring(duration: 1)
                case .finish:
                    return .easeInOut(duration: 0.4)
                }
            }
    }
}

With these modifications, the MorphShapeView will smoothly transition through the defined phases, applying the appropriate modifiers and animations to achieve the desired effect.


Phase animations open a whole new world of opportunities for iOS developers using SwiftUI. With the new PhaseAnimator feature, the possibilities for highly customisable animations are endless. The key lies in understanding the flow and usage of this new tool.

Hopefully, this guide has shed some light on that, providing you with the confidence to create your phase animations in SwiftUI. Dive in, experiment, and have fun creating exciting and dynamic user interfaces!

In the next posts, we'll explore keyframe animations in SwiftUI and animating SF Symbols, taking your SwiftUI animations to the next level.