Search code examples
swiftanimationswiftui

Custom fullScreenCover animation


Is it possible to add a custom animation to a fullScreenCover? The default animation has been disabled but I am struggling in finding a way to add a custom animation.

I guess that transaction.disablesAnimations = true disables any animation that is added, but I didn't find any other way to disable the default animation.

I know that there are alternative ways of implementing something like this (fallback to UIKit or using an overlay), but it would be interesting if it could be done using a fullScreenCover.

struct ContentView: View {
    @State private var isPresentingFullScreenCover = false

    var body: some View {
        Button("Show FullScreenCover") {
            isPresentingFullScreenCover = true
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(.black)
        .fullScreenCover(isPresented: $isPresentingFullScreenCover) {
            FullScreenCoverView()
        }
        .transaction { transaction in
            transaction.disablesAnimations = true
        }
    }
}

struct FullScreenCoverView: View {
    @Environment(\.dismiss) var dismiss

    var body: some View {
        Button("Dismiss") {
            dismiss()
        }
    }
}

Solution

  • You have successfully disabled the normal transition. So all you need to do now is:

    • hide the presentation background
    • show and hide the content using your own animated transition.

    The animation that you add can be triggered by toggling a flag in .onAppear and .onDisappear:

    struct FullScreenCoverView: View {
        @Environment(\.dismiss) var dismiss
        @State private var isShowing = false
    
        var body: some View {
            ZStack {
                Color.clear
                if isShowing {
                    Button("Dismiss") {
                        withAnimation {
                            isShowing = false
                        } completion: {
                            dismiss()
                        }
                    }
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(.background)
                    .transition(.scale.animation(.easeInOut))
                }
            }
            .ignoresSafeArea()
            .presentationBackground(.clear)
            .onAppear { isShowing = true }
            .onDisappear { isShowing = false }
        }
    }
    

    Animation