In my project I have a root view which contains several NavigationLinks. The links work, however the animation only works on one of them. I've created a very simple example project to highlight the issue. So I have a content view like this:
struct ContentView: View {
@StateObject var viewModel: ContentViewModel
var body: some View {
NavigationView {
VStack {
Text("Content view")
Button {
viewModel.goToTapped(.details)
} label: {
Text("To Details")
}
navigationLinks
}
.padding()
}
}
private var navigationLinks: some View {
HStack {
NavigationLink(
destination: DetailsView(viewModel: viewModel)
.navigationBarHidden(true),
tag: ContentViewModel.ViewState.details,
selection: $viewModel.viewState
) { EmptyView() }
NavigationLink(
destination: ContentView(viewModel: .init())
.navigationBarHidden(true),
tag: ContentViewModel.ViewState.content,
selection: $viewModel.viewState
) { EmptyView() }
NavigationLink(
destination: PaymentView(viewModel: viewModel)
.navigationBarHidden(true),
tag: ContentViewModel.ViewState.payment,
selection: $viewModel.viewState
) { EmptyView() }
NavigationLink(
destination: CardView(viewModel: viewModel)
.navigationBarHidden(true),
tag: ContentViewModel.ViewState.card,
selection: $viewModel.viewState
) { EmptyView() }
}
}
}
The associate viewModel:
class ContentViewModel: ObservableObject {
enum ViewState {
case content
case details
case payment
case card
}
@Published var viewState: ViewState?
func goToTapped(_ viewState: ViewState) {
self.viewState = viewState
}
}
DetailsView:
struct DetailsView: View {
@ObservedObject var viewModel: ContentViewModel
var body: some View {
VStack {
Text("Details View")
Button {
viewModel.goToTapped(.payment)
} label: {
Text("To Payment")
}
Button {
viewModel.goToTapped(.content)
} label: {
Text("Back to Content")
}
}
}
}
PaymentView:
struct PaymentView: View {
@ObservedObject var viewModel: ContentViewModel
var body: some View {
NavigationView {
VStack {
Text("Payment View")
Button {
viewModel.goToTapped(.card)
} label: {
Text("To Card")
}
Button {
viewModel.goToTapped(.details)
} label: {
Text("Back To Details")
}
}
}
}
}
CardView:
struct CardView: View {
@ObservedObject var viewModel: ContentViewModel
var body: some View {
Text("Card view")
Button {
viewModel.goToTapped(.payment)
} label: {
Text("Back To Payment")
}
}
}
And here is the result:
So it seems that when the NavigationLink is declared within the same view as the transition trigger, the animation works fine. However, once we have navigated to a new view, whilst the navigation works, the animation does not.
I tried moving the NavigationLinks into the individual views, but of course because we are listening to the same viewState publisher for all views, this does not work because as soon as the viewState is changes, the the navigation stack dismisses and we go back to the root view (ContentView).
How can declare multiple NavigationLinks like this within a root view without impacting on the navigation animation?

UPDATE
So in iOS 16 we now have
NavigationStack. This works fine when I replaceNavigationViewwithNavigationStack- however my app needs to support iOS14+ so wondering what I can use for earlier versions...