I am working on a SwiftUI project that has a loginView (Root view embedded in NavigationStack). When I push to registration screen (Screen A) using .navigationDestination(...) modifier and then to another screen (Screen B). When I want to pop to the previous screen (Screen A) from (Screen B) it navigates me to the root (login screen) instead of Screen (B) my code:
NOTE* When I am using NavigationLink for pushing then its working fine. but NavigationLink is deprecated and Apple suggest to use NavigationDestination modifier.
// LoginView (Root view)
struct LoginView: View {
@State var moveToScreenA: Bool = false
var body: some View {
NavigationStack {
VStack(alignment: .leading, spacing: 0, content: {
Button {
self.moveToScreenA = true
} label: {
Text("Registration")
}
})
.navigationDestination(isPresented: $moveToScreenA) {
ScreenA()
}
}
}
}
// Screen A
struct ScreenA: View {
@State var moveToScreenB: Bool = false
var body: some View {
NavigationStack {
VStack(alignment: .leading, spacing: 0, content: {
Button {
self.moveToScreenB = true
} label: {
Text("Next")
}
})
.navigationDestination(isPresented: $moveToScreenB) {
ScreenB()
}
}
}
}
// Screen B
struct ScreenB: View {
@Environment(\.dismiss) var dismiss
var body: some View {
NavigationStack {
VStack(alignment: .leading, spacing: 0, content: {
Button {
self.dismiss()
} label: {
Image(.BACK_DARK)
}
})
}
}
}
You just need a single NavigationStack
here, on LoginView
, then use NavigationPath
to navigate to the sub-views. Try this:
struct LoginView: View {
@State var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
VStack(alignment: .leading, spacing: 0, content: {
Button {
path.append("A")
} label: {
Text("Registration")
}
})
.navigationDestination(for: String.self) { string in
if string == "A" {
ScreenA(path: $path)
} else {
ScreenB(path: $path)
}
}
.navigationTitle("Root")
}
}
}
Then remove NavigationStack
outer from ScreenA and ScreenB. Use navigationDestination
for concrete type to distinguish the correct destination.
struct ScreenA: View {
@Binding var path: NavigationPath
var body: some View {
VStack(alignment: .leading, spacing: 0, content: {
Button {
path.append("B")
} label: {
Text("Next")
}
})
.navigationTitle("Screen A")
}
}
struct ScreenB: View {
@Environment(\.dismiss) var dismiss
@Binding var path: NavigationPath
var body: some View {
VStack(alignment: .leading, spacing: 0, content: {
Button {
path = Navigation() //<- back to the root
} label: {
Image(systemName: "star")
}
})
.navigationTitle("Screen B")
}
}
Example for navigation destination with another type in sub view.
struct ScreenA: View {
@Binding var path: NavigationPath
var body: some View {
VStack(alignment: .leading, spacing: 0, content: {
Button {
path.append(true)
} label: {
Text("Next")
}
})
.navigationDestination(for: Bool.self) { _ in
ScreenB(path: $path)
}
.navigationTitle("Screen A")
}
}