Reputation: 20138
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?
Upvotes: 21
Views: 21664
Reputation: 92409
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")
}
}
}
Upvotes: 3
Reputation: 310
Why not use an overlay instead?
.overlay {
if isLoading {
ZStack {
ProgressView()
}
.background(BackgroundCleanerView())
}
}
Upvotes: -3
Reputation: 257493
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
Upvotes: 23
Reputation: 2455
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
}
Upvotes: 40
Reputation: 1274
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)
}
}
Upvotes: 8
Reputation: 502
.fullScreenCover(isPresented: isPresented) {
content()
.background(TransparentBackground())
}
.transaction({ transaction in
transaction.disablesAnimations = true
})
this should work, based on @asamoylenko's answer
Upvotes: 19