Back to root View #8
Replies: 1 comment
-
Hi @khairilushan, Thank you for initiating this thread. I'm looking for the best way to navigate back to the root in a state-driven navigation system. One idea involves using NavigationStacks. The Pointfree discussed navigation stacks in episode 213 - SwiftUI Navigation: Stacks. I have created a small proof of concept project. There are three screens - A, B, and C. A user can navigate from screen A to screen B, and from screen B to screen C. On screen C, the user can finish the flow, which should then return them to the root (screen A).
I modeled state-driven navigation using navigation stacks and a closure delegation approach. The primary issue with this implementation is that screen A has a screen C destination, even though it is not possible to navigate directly from screen A to screen C. // Screen A
class ScreenAModel: ObservableObject {
enum Destination: Hashable {
case screenB(ScreenBModel)
case screenC(ScreenCModel) // screen A has a screen C destination, even though it is not possible to navigate directly from screen A to screen C
}
@Published var path: [Destination] {
didSet { self.bind() }
}
init(path: [Destination] = []) {
self.path = path
}
func onGoToScreenBButtonTapped() {
path.append(.screenB(ScreenBModel()))
}
func bind() {
for destination in self.path {
switch destination {
case let .screenB(model):
model.onTapScreenC = { [weak self] in
guard let self else { return }
self.path.append(.screenC(ScreenCModel()))
}
case let .screenC(model):
model.onTapFinishFlow = { [weak self] in
guard let self else { return }
self.path = []
}
}
}
}
}
struct ScreenAView: View {
@ObservedObject var model: ScreenAModel
var body: some View {
NavigationStack(path: $model.path) {
Button {
model.onGoToScreenBButtonTapped()
} label: {
Text("Go to Screen B")
}
.navigationDestination(for: ScreenAModel.Destination.self) { destination in
switch destination {
case let .screenB(model):
ScreenBView(model: model)
case let .screenC(model):
ScreenCView(model: model)
}
}
.navigationTitle("Screen A")
}
}
}
// Screen B
class ScreenBModel: ObservableObject, Hashable {
var onTapScreenC: () -> Void = {}
func onGoToScreenCButtonTapped() {
onTapScreenC()
}
}
struct ScreenBView: View {
@ObservedObject var model: ScreenBModel
var body: some View {
Button {
model.onGoToScreenCButtonTapped()
} label: {
Text("Go to Screen C")
}
.navigationTitle("Screen B")
}
}
// Screen C
class ScreenCModel: ObservableObject, Hashable {
var onTapFinishFlow: () -> Void = {}
func onFinishFlowButtonTapped() {
onTapFinishFlow()
}
}
struct ScreenCView: View {
@ObservedObject var model: ScreenCModel
var body: some View {
Button {
model.onFinishFlowButtonTapped()
} label: {
Text("Finish the flow")
}
.navigationTitle("Screen C")
}
} Is there a better way to model the navigation more accurately so that it is clear that a user can navigate from screen A to screen B, and still be able to pop to the root from screen C? 🙏 |
Beta Was this translation helpful? Give feedback.
-
Hi everyone,
Let's say we have navigation stack that looks like this: A - B - C . And I want to navigate back from C to A. Currently with swiftui-navigation here is how I do it:
As we can see, I keep on passing the
firstRoute
to all theView
s. Is that how we should do it? Or is there any other better practice?Thanks everyone.
Beta Was this translation helpful? Give feedback.
All reactions