In SwiftUI with attached code when i set navigationBarBackButtonHidden
to true, the NavigationStack's navigation bar always pushes in when I dismiss the detail view. Since it's a zoom transition, I want the navigation bar to stay and not animate. How do i solve this?
import SwiftUI
struct ContentView: View {
@Namespace private var namespace
var body: some View {
NavigationStack {
NavigationLink {
DetailView()
// here is the issue: if I set it to true, it will have that default push animation when dismissed, which is inconsistent with the zoom animation.
.navigationBarBackButtonHidden(false)
.navigationTransition(.zoom(sourceID: "world", in: namespace))
} label: {
Image(systemName: "globe")
.matchedTransitionSource(id: "world", in: namespace)
}
.navigationTitle("Main")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .primaryAction){
Button {
print("noop")
} label: {
Label("Toggle", systemImage: "rectangle.grid.1x2")
}
}
}
}
}
}
struct DetailView: View {
var body: some View {
ZStack{
Color.indigo
Text("body here")
}.ignoresSafeArea()
}
}
#Preview {
ContentView()
}
The animation seems to be associated with the navigation bar being removed, because there is no content.
The workaround you showed in your answer is retaining some content, so the navigation bar is not removed.
You could also try setting a navigation title:
DetailView()
.navigationBarBackButtonHidden(true)
.navigationTransition(.zoom(sourceID: "world", in: namespace))
.navigationTitle("Detail") // ๐ here
.navigationBarTitleDisplayMode(.inline) // ๐ and here
If you don't want to set a title then you can force the navigation bar to remain visible anyway, by applying .toolbarVisibility(.visible, for: .navigationBar)
.
DetailView()
.navigationBarBackButtonHidden(true)
.navigationTransition(.zoom(sourceID: "world", in: namespace))
.navigationBarTitleDisplayMode(.inline)
.toolbarVisibility(.visible, for: .navigationBar)
.toolbarBackgroundVisibility(.hidden, for: .navigationBar)
EDIT Following up on your comment:
The goal is to not have any extra vertical space taken. This solution even with inline title still takes some good vertical space... are there better solutions?
If a state variable is used to control the visibility of the navigation bar then it can be hidden when navigating to the detail view, which means it no longer uses any space:
@State private var navBarVisibility = Visibility.visible
.hidden
in .onAppear
for the detail view..visible
in .onAppear
for the navigation link..onAppear
is not called. As a fallback, the variable should be set to .visible
in an .onDisappear
callback for the detail view too..onDisappear
callback to the link as well.NavigationStack {
NavigationLink {
DetailView()
.navigationBarBackButtonHidden(true)
.navigationTransition(.zoom(sourceID: "world", in: namespace))
.navigationBarTitleDisplayMode(.inline)
.toolbarVisibility(navBarVisibility, for: .navigationBar)
.onAppear { navBarVisibility = .hidden }
.onDisappear { navBarVisibility = .visible }
} label: {
Image(systemName: "globe")
.matchedTransitionSource(id: "world", in: namespace)
}
.onAppear { navBarVisibility = .visible }
.onDisappear { navBarVisibility = .hidden }
.navigationTitle("Main")
.navigationBarTitleDisplayMode(.inline)
.toolbarVisibility(navBarVisibility, for: .navigationBar)
.toolbar {
// ... as before
}
}