TL;DR: You can suppress default transition animations in SwiftUI’s
Sheet
andNavigationStack
by using aTransaction
withdisablesAnimations
set totrue
. Wrap your state changes inwithTransaction
to disable animations selectively.
Background
SwiftUI provides default transition animations for components like Sheet
, FullScreenCover
, and NavigationStack
. However, in certain scenarios—such as deep link navigation—developers may prefer to directly reach the target state without transition animations.
Implementation
While it’s not possible to directly turn off transition animations for these components, you can achieve this effect by customizing a Transaction
and setting disablesAnimations
to true
.
Example: Disabling Sheet
Animations
Swift
struct SheetDemo: View {
@State private var isActive = false
var body: some View {
List {
Button("Pop Sheet without Animation") {
var transaction = Transaction(animation: .none)
transaction.disablesAnimations = true
withTransaction(transaction) {
isActive.toggle()
}
}
Button("Pop Sheet with Animation") {
isActive.toggle()
}
}
.sheet(isPresented: $isActive) {
VStack {
Button("Dismiss without Animation") {
var transaction = Transaction(animation: .none)
transaction.disablesAnimations = true
withTransaction(transaction) {
isActive.toggle()
}
}
Button("Dismiss with Animation") {
isActive.toggle()
}
}
.buttonStyle(.borderedProminent)
}
}
}
Demonstration
Example: Disabling NavigationStack
Animations
Swift
struct NavigationStackDemo: View {
@State var pathStore = PathStore()
var body: some View {
@Bindable var pathStore = pathStore
NavigationStack(path: $pathStore.path) {
List {
Button("Go Link without Animation") {
var transaction = Transaction(animation: .none)
transaction.disablesAnimations = true
withTransaction(transaction) {
pathStore.path.append(1)
}
}
Button("Go Link with Animation") {
pathStore.path.append(1)
}
}
.navigationDestination(for: Int.self) {
ChildView(store: pathStore, n: $0)
}
}
}
}
@Observable
class PathStore {
var path: [Int] = []
}
struct ChildView: View {
let store: PathStore
let n: Int
@Environment(\.dismiss) var dismiss
var body: some View {
List {
Text("\(n)")
Button("Dismiss without Animation") {
var transaction = Transaction(animation: .none)
transaction.disablesAnimations = true
withTransaction(transaction) {
store.path = []
}
}
Button("Dismiss with Animation") {
dismiss()
}
}
}
}
Demonstration
Considerations
- Localized Effect
The
Transaction
settings only affect operations within thewithTransaction
closure. Other operations remain unaffected. - Animation Suppression Rules
Since
withTransaction
suppresses all animations caused by state changes within its closure, ensure that unrelated state changes are excluded to avoid inadvertently disabling other animations.