12

I have this view:

struct TheFullCover: View {
    
    @State var showModal = false
    
    var body: some View {
        
        
        Button(action: {
            showModal.toggle()
        }) {
            Text("Show Modal")
                .padding()
                .foregroundColor(.blue)
            
        }
        .background(Color(.white))
        .overlay(
            RoundedRectangle(cornerRadius: 10)
                .stroke(.red, lineWidth:1)
        )
        .fullScreenCover(isPresented: $showModal, onDismiss: {
            
        }, content: {
            VStack {
                Text("Here I am")
                TheFullCover()
            }
        })
        
    }
    
    
}

Every time I press the Button, the modal screen comes up fullscreen. All works great.

Question:

How do I disable the slide up animation? I want the view to be presented immediately fullscreen without animating to it.

Is there a way to do that?

zumzum
  • 17,984
  • 26
  • 111
  • 172
  • I don't think you can disable the system animation of `fullScreenCover` (unless maybe the user has an accessibility option for reduced motion on). I'd probably just use a `ZStack` and present the view on top without animation. – jnpdx Oct 25 '21 at 19:03

6 Answers6

18

AFAIK the proper to do it as of today is using transaction https://developer.apple.com/documentation/swiftui/transaction

var transaction = Transaction()
transaction.disablesAnimations = true
withTransaction(transaction) {
   showModal.toggle()
}

I also created a handy extension for this:

extension View {
    func withoutAnimation(action: @escaping () -> Void) {
        var transaction = Transaction()
        transaction.disablesAnimations = true
        withTransaction(transaction) {
            action()
        }
    }
}

which can be used like this:

withoutAnimation {
    // do your thing
}
asamoylenko
  • 2,107
  • 2
  • 18
  • 13
15

A possible solution is to disable views animation completely (and then, if needed, enable again in .onAppear of presenting content), like

    Button(action: {
        UIView.setAnimationsEnabled(false)    // << here !!
        showModal.toggle()
    }) {

and then

    }, content: {
        VStack {
            Text("Here I am")
            TheFullCover()
        }
        .onAppear {
            UIView.setAnimationsEnabled(true)    // << here !!
        }
    })

Tested with Xcode 13 / iOS 15

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
9
.fullScreenCover(isPresented: isPresented) {
    content()
        .background(TransparentBackground())
}
.transaction({ transaction in
    transaction.disablesAnimations = true
})

this should work, based on @asamoylenko's answer

5

At the moment, I find it easier to use UIKit for presentation in SwiftUI.

someView
  .onChange(of: isPresented) { _ in
    if isPresented {
      let vc = UIHostingController(rootView: MyView())
      vc.modalPresentationStyle = .overFullScreen
      UIApplication.shared.rootVC?.present(vc, animated: false)
    } else {
      UIApplication.shared.rootVC?.dismiss(animated: false)
    }
  }
congnd
  • 1,168
  • 8
  • 13
  • I like this approach. Not saying it's by the book or anything, but considering SwiftUI still has a long way to go to be production ready for real, this seems like a valid option. Thanks – zumzum Jul 20 '22 at 02:32
0

You can disable animations when presenting or dismissing a View by wrapping the state / binding mutation in withTransaction(_:_:) and setting the transaction's disablesAnimations property to true.

The following Swift 5.9 / iOS 17 example shows a possible implementation to disable animations when a View is presented with fullScreenCover or dismissed:

import SwiftUI

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

    var body: some View {
        NavigationStack {
            Form {
                Button("Present (with animation)") {
                    isPresentingFullScreenView = true
                }
                Button("Present (no animation)") {
                    var transaction = Transaction()
                    transaction.disablesAnimations = true
                    withTransaction(transaction) {
                        isPresentingFullScreenView = true
                    }
                }
            }
            .fullScreenCover(isPresented: $isPresentingFullScreenView) {
                FullScreenView(isPresentingFullScreenView: $isPresentingFullScreenView)
            }
            .navigationTitle("Content view")
        }
    }
}
import SwiftUI

struct FullScreenView: View {
    @Binding var isPresentingFullScreenView: Bool

    var body: some View {
        NavigationStack {
            Form {
                Button("Dismiss (with animation)") {
                    isPresentingFullScreenView = false
                }
                Button("Dismiss (no animation)") {
                    var transaction = Transaction()
                    transaction.disablesAnimations = true
                    withTransaction(transaction) {
                        isPresentingFullScreenView = false
                    }
                }
            }
            .navigationTitle("Full screen view")
        }
    }
}
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
-2

Why not use an overlay instead?

.overlay {
        if isLoading {
            ZStack {
                ProgressView()
            }
            .background(BackgroundCleanerView())
        }
    }
chitgoks
  • 311
  • 2
  • 6
  • 17
  • 1
    how will overlay cover full screen including tabs with proper animation ? – Asadullah Ali Feb 01 '23 at 20:17
  • place the overlay at the root most view? what do you mean with proper animation? didnt the OP say full screen cover with no animation? – chitgoks Feb 02 '23 at 04:06
  • if the tabview has more children of navigation then we may have to add all of the children popups to root. For example if I'm showing tooltips on 20 internal views then i'll have to pass bindings from root ? – Asadullah Ali Feb 03 '23 at 09:29
  • ok. i guess since i only have 1 popup for 1 tab out fo 3 it worked for me. – chitgoks Feb 04 '23 at 01:41