I am trying to use Combine to route SwiftUI views, and it sort of works, but has some unwanted behaviour that I hope someone can help me with. I made an example project which only contains two files, ViewRouter.swift
and ViewController.swift
that just contains a @IBSegueAction
to return a UIHostingController
:
The class ViewRouter
is a ViewModel
for the SwiftUI Views that contains a @ViewBuilder
property. When the SwiftUI
views calls the didFinish()
function, the step
property is set to the next View
.
class ViewRouter: ObservableObject {
enum Step { case test1, test2, test3, test4 }
@Published var step: Step = .test1
@ViewBuilder var nextStepView: some View {
switch step {
case .test1:
Test1(router: self)
case .test2:
Test2(router: self)
case .test3:
Test3(router: self)
case .test4:
Test4(router: self)
}
}
func didFinish() {
switch step {
case .test1:
step = .test2
case .test2:
step = .test3
case .test3:
step = .test4
case .test4:
break
}
}
}
This works perfect for Test1
, when tapping the Next
link, the Test1
view is animated to the left, to reveal Test2
. When tapping Next
in Test2
however, the Test2
is animated to the left to reveal Test3
, but then immediately it animates back to the right to reveal the same Test3
view. Exactly the same happens when tapping Next
in Test3
.
And tapping the back button always ends up in Test1
view.
All four views are the same, apart from the text in Text
:
struct Test1: View {
@ObservedObject var router: ViewRouter
@State var nextView = false
var body: some View {
VStack {
NavigationLink(destination: router.nextStepView, isActive: $nextView) {
EmptyView()
}
Text("Test1")
Button(action: {
nextView = true
router.didFinish()
}, label: {
Text("Next")
})
}
}
}