I have this structure in my SwiftUI application:
Main container
holds a NavigationView
with two NavigationLinks
, V1
and V4
.
From there, I can go to View1
, View2
and View3
which I can navigate through with V1
, V2
and V3
NavigationLinks
.
I can go to a ResultView
with the proper NavigationLinks
Result1
, Result2
, Result3
.
I have an EnvironmentObject
that holds all the bool
flags for the isActive
property of the NavigationLinks
.
When I reach ResultView, I need to pop the views and go to V4, without being able to access V1, V2 and V3 until later.
The problem is that the following shenanigans happen (on iPhone 8, iOS 13.4.1):
- If I set
V1 = false
thenV4 = true
, theNavigationView
has a weird behavior where it pops to whatever was its previous view (View1, View2 or View3) then goes to View4, then goes back to MainContainer. - If I only set
V1 = false
, it pops correctly toMain container
I need to set V2, V3, Result1, Result2 and Result3 back to false
, to ensure I can restart from V1 and then go to V2, etc.
Also, one of the requirements of my app is that I can't absolutely go back to View1
, View2
and View3
after going to ResultView
.
I've thought of two possible solutions but each one has it caveats:
- Hide a
NavigationLink
forView 4
inResultView
: How could I prevent going back to View1, 2 or 3 when pressingBack
fromV4
, and presentMain container
instead? - Use a
Timer
orDispatchQueue.main.asyncAfter
to setV4 = true
after settingV1 = false
: seems a hacky solution, but I've already tried this and it has the same effect as not using it, plus I don't want to see a transition back and forth (just forth).
Do you have any suggestion on why the NavigationLinks
do not behave correctly, or perhaps a better navigation model?
I've already implemented a solution where I'm using a custom Navigation Stack, where I can push and pop each screen whenever I want, the problem is that I lose some of the transitions and I'd really like to achieve this by using the standard NavigationLinks
.
I'm leaving an example here.
import SwiftUI
class NavigationCoordinator: ObservableObject {
@Published var goToFirstScreen: Bool = false
@Published var goToSecondScreen: Bool = false
@Published var goToThirdScreen: Bool = false
@Published var goToFourthScreen: Bool = false
}
struct ContentView: View {
@EnvironmentObject var coordinator: NavigationCoordinator
var body: some View {
NavigationView {
VStack {
Spacer()
NavigationLink(destination: FirstScreen(), isActive: self.$coordinator.goToFirstScreen) {
Text("Go To View1!")
}
Spacer()
NavigationLink(destination: FourthScreen(), isActive: self.$coordinator.goToFourthScreen) {
Text("Go to View4!")
}
Spacer()
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct FirstScreen: View {
@EnvironmentObject var coordinator: NavigationCoordinator
var body: some View {
NavigationLink(destination: SecondScreen(), isActive: self.$coordinator.goToSecondScreen) {
Text("Go to View2!")
}
}
}
struct SecondScreen: View {
@EnvironmentObject var coordinator: NavigationCoordinator
var body: some View {
NavigationLink(destination: ThirdScreen(), isActive: self.$coordinator.goToThirdScreen) {
Text("Go to View3!")
}
}
}
struct ThirdScreen: View {
@EnvironmentObject var coordinator: NavigationCoordinator
var body: some View {
Button("Go to View4") {
self.coordinator.goToFirstScreen = false
self.coordinator.goToFourthScreen = true
}
}
}
struct FourthScreen: View {
@EnvironmentObject var coordinator: NavigationCoordinator
var body: some View {
Button("Pop to root!") {
self.coordinator.goToFourthScreen = false
}
}
}