8

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?

2
  • please do not ask more than one question in one post, it makes harder to find the right answer for you also others to use your question to learn or study. Commented Apr 16, 2021 at 16:56
  • To be fair, if one is coming at it from a UIKit perspective, this would be one concept. It just happens that in SwiftUI, it is more likely to be two separate issues. Commented Apr 16, 2021 at 17:05

2 Answers 2

5

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")
            }
        }
    }
}

Sign up to request clarification or add additional context in comments.

Comments

1

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

2 Comments

It's a pity that it's only supported from iOS 16 :)
Luckily there is a backport of the NavigationStack to iOS 14: github.com/lm/navigation-stack-backport

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.