Search code examples
swiftuiswiftui-navigationlinkswiftui-navigationview

Open new view and close the current one in NavigationLink


This is the Login() view:

struct Login: View {
    @Environment(\.presentationMode) var presentationMode

    var body: some View{
        
        VStack{
            
            HStack{
                                    
                Button(action: {
                    
                    presentationMode.wrappedValue.dismiss()

                }) {
                    Image(systemName: "xmark")
                        .resizable()
                        .frame(width: 18, height: 18)
                }

            }
            
            
            NavigationLink(destination: CreateAccount().navigationBarBackButtonHidden(true), label: {
                Text("create account")
                
                // and close the current view Login()
            })                
        }       
    }
}

Is it possible to open a new view, in this case CreateAccount() and closing the current view Login()?


Solution

  • In order to do this, I would suggest skipping the NavigationView altogether, see here for more info. An example for your situation:

    //You need an `ObservedObject` to do this, and a overall holder view
    
    enum ViewStates {
        // Declare possible views
        case ContentView
        case Login
        case CreateAccount
    }
    
    // Then use an observableObject
    
    class viewControl: ObservableObject {
        @Published var currentView: ViewStates = .ContentView
    }
    
    //Finally, pass this into your views. Take a look at the second part of the tutorial I posted below for more info
    //such as using `EnvironmentObject` and adding animation. Example implementation below:
    
    struct ControllerView: View {
    @StateObject var controller: viewControl
    
    var body: some View {
    switch controller.currentView {
    case .ContentView:
    ContentView(controller: controller)
    case .Login:
    Login(controller: controller)
    case .CreateAccount:
    CreateAccount(controller: controller)
    }
    }
    }
    

    Next, you need to have @ObservedObject var controller: viewControl in all of your views. Note that you don't need a default statement in the switch clause, because the enum declares all possible values.

    The following is an example CreateAccount view. You also no longer need the dismiss - in fact, that will no longer work.

    struct CreateAccount: View{
    @ObservedObject var controller: viewControl
    
    var body: some View{
    //Content
    Button("Dismiss"){
    controller.currentView = .ContentView
    }
    }
    
    }
    

    This will allow you to switch the view by clicking. Instead of a NavigationLink in ContentView, do this:

    Button{
    controller.currentView = .CreateAccount
    } label: {
    Text("Create Account")
    }
    
    

    To go back, you just set the value again. This can also be expanded to show more views.

    Second part of the tutorial