Search code examples
iosswiftiphoneswiftuiswiftui-animation

How can I reverse the slide transition for a SwiftUI animation?


I'm working on a sequence of screens that should change on a button press and should slide in/out from right to left.
Everything is working nicely except the .slide transition makes it move in from the leading edge and move out to the trailing edge. (from left to right)
I want to reverse the transition animation direction without changing what trailing/leading is (at least not in the whole context of the app).

I tried changing the transition to .move(edge: .trailing) but then the views move in and out from the same direction.

import SwiftUI

struct ContentView: View {
    enum screens {
        case start, mid, final
    }
    @State var curScreen: screens = .start
    
    func changeScreen() {
        switch curScreen {
        case .start:
            curScreen = .mid
        case .mid:
            curScreen = .final
        case .final:
            return
        }
    }
    
    var body: some View {
        switch curScreen {
        case .start:
            ScreenView(callback: changeScreen, text: "Start")
                .transition(.slide)
        case .mid:
            ScreenView(callback: changeScreen, text: "Mid")
                .transition(.slide)
        case .final:
            ScreenView(callback: {}, text: "Final")
                .transition(.slide)
        }
    }
}

struct ScreenView: View {
    let callback: () -> ()
    let text: String
    var body: some View {
        Text(text)
            .padding()
            .frame(maxWidth: .infinity)
            .onTapGesture {
                withAnimation(.default) {
                    callback()
                }
            }
    }
}

Solution

  • @Asperi has already answered my question, but it didn't show up on google or stackoverflow when I searched for it, so here again for the algorithm:

    How to reverse the slide transition in SwiftUI:

    Taken from the Apple Developer Documentation:

    static var slide: AnyTransition
    // A transition that inserts by moving in from the leading edge, and removes by moving out towards the trailing edge.
    

    Which can also be written as:

    AnyTransition.asymmetric(
        insertion: .move(edge: .leading),
        removal: .move(edge: .trailing)
    )
    

    So to reverse the animation just flip insertion and removal and put that in your transition ViewModifier.

    Since I needed to use it a few times I made an extension to AnyTransition so I can just call .transition(.backslide)

    extension AnyTransition {
        static var backslide: AnyTransition {
            AnyTransition.asymmetric(
                insertion: .move(edge: .trailing),
                removal: .move(edge: .leading))}
    }