badadin
badadin

Reputation: 577

Remove screen from navigation stack in SwiftUI

I'm using NavigationLink to navigate screens in NavigationView. How can I remove screen from navigation stack? Not just hide the navigation "Back" button but completely remove screen from stack?

For example, I have screen chain like this: A -> B -> C How can I remove screen B to go back from C to A?

Or, another example, how to remove screen A and B, so the C screen will be the root?

Or all of this is impossible by conception of SwiftUI?

Upvotes: 9

Views: 8217

Answers (2)

Matias Contreras
Matias Contreras

Reputation: 500

There is a new element in SwiftUI called NavigationStack which lets you manipulate the stack any way you want. I have been playing with it in an example project attempting to use it in a maintainable and programatic approach to coordinators in SwiftUI

Upvotes: 1

jnpdx
jnpdx

Reputation: 52312

In terms of your first question (going from C to A), this is often called "popping to root" and has a number of solutions here on SO, including: https://stackoverflow.com/a/59662275/560942

Your second question (replacing A with C as the root view) is a little different. You can do that by replacing A with C in the view hierarchy. In order to do this, you'd need to have some way to communicate with the parent view -- I chose a simple @State/@Binding to do this, but one could use an ObservableObject or even callback function instead.

enum RootView {
    case A, C
}

struct ContentView : View {
    @State private var rootView : RootView = .A
    
    var body: some View {
        NavigationView {
            switch rootView {
            case .A:
                ViewA(rootView: $rootView)
            case .C:
                ViewC(rootView: $rootView)
            }
        }.navigationViewStyle(StackNavigationViewStyle())
    }
}

struct ViewA : View {
    @Binding var rootView : RootView
    
    var body: some View {
        VStack {
            Text("View A")
            NavigationLink(destination: ViewB(rootView: $rootView)) {
                Text("Navigate to B")
            }
        }
    }
}

struct ViewB : View {
    @Binding var rootView : RootView
    
    var body: some View {
        VStack {
            Text("View B")
            NavigationLink(destination: ViewC(rootView: $rootView)) {
                Text("Navigate to C")
            }
            Button(action: {
                rootView = .C
            }) {
                Text("Navigate to C as root view")
            }
        }
    }
}

struct ViewC : View {
    @Binding var rootView : RootView
    
    var body: some View {
        VStack {
            Text("View C")
            switch rootView {
            case .A:
                Button(action: {
                    rootView = .C
                }) {
                    Text("Switch this to the root view")
                }
            case .C:
                Text("I'm the root view")
            }
        }
    }
}

Upvotes: 5

Related Questions