SwiftUI Transitions

Adding and removing views with animation

published on September 7, 2025

Recently, we have learnt what are the different ways of animating the appearance of SwiftUI views. Check out SwiftUI Animation Techniques and Animate your drawings with SwiftUI if you want to learn more. In this article, we are going to have a look at how transitioning between views, or adding/removing views, can be animated using, drum roll, Transitions. As with everything in SwiftUI, the basics are very simple but even more really complex stuff can be achieved with a bit of work. Let's dive into it!

1. Simple insertion/removal transitions

In a SwiftUI layout, you can control conditionally add or remove a view by simply using an if statement, like shown below. As we have discussed in previous articles, any state that changes within a withAnimation block will result in an animation on the UI. By default SwiftUI uses a fade transition to show or hide the view.

VStack {
    Button("Toggle") {
        withAnimation {
            show.toggle()
        }
    }
    
    if show {
        Text("This text has transitions")
    }
}

transition fade

Customising the transition is also very simple. SwiftUI comes with a series of different built in transitions that you can choose from. Use the transition modifier to do so:

Text("Slide")
    .transition(.slide)
Text("Move")
    .transition(.move(edge: .trailing))
Text("Scale")
    .transition(.scale)

transition fade

💡 In case you were wondering, slide and move are very similar but slide always comes in from the leading edge, leaving towards the trailing one while for move, you can customize the edge the view moves towards and it uses the same edge both for insertion and removal. Their animation is also slightly different

If you didn't find the perfect transition yet, try combining multiple ones together using the combined method of Transition. This way, you can fine tune, how exactly your views show up or disappear.

In case you want your views to have different transitions for insertion and removal, that is also possible using the asymmetric function.

Text("Asymetric")
    .transition(.asymmetric(insertion: .scale, removal: .slide))
Text("Slide + Scale")
    .transition(.slide.combined(with: .scale))

combined

2. Custom transitions

For even greater control, we can define our own transitions. Defining custom transitions consists of three easy steps:

  1. Creating a ViewModifier
  2. Creating an extension for AnyTransition
  3. Applying the transition just like anything else

Let's see what we are building:

combined

This is a quite simple animation, but illustrates the process very well. Let's start by creating the ViewModifier

struct RotationTransition: ViewModifier {
    let value: Bool
    
    func body(content: Content) -> some View {
        content
            .rotationEffect(.degrees(value ? 0 : 360))
            .offset(y: value ? 0 : 100)
            .scaleEffect(value ? 1 : 0.01)
            .opacity(value ? 1 : 0)
    }
}

As you can see, the modifier receives a value and constructs two states of the view based on the value. Note that this is a simple view modifier, you could use it in any other situation where you would any other modifier.

Now, let's create an extension:

extension AnyTransition {
    static var rotation: AnyTransition {
        .modifier(active:  RotationTransition(value: false),
                  identity: RotationTransition(value: true))
    }
}

The most important part of this is the .modifier call. Note that this is different from the modifier you would use for your views. It takes two arguments: active and identity. Active is the state when your view is transitioning while identity represents the resting state of the view. You don't need to handle the direction of the animations as SwiftUI automatically handles the transition between the two states.

The last step is rather simple, all we need to do is applying the transition to the view

Text("Title")
    .transition(.rotation)
Follow me on X