Search code examples
swiftuinavigationviewswiftui-navigationlink

Navigating back to main menu View in SwiftUI with Alert Button


I have an app with two defined views. I use NavigationView to move between them. I wanted the alert button to switch users back to Main Menu View and I have even found an answer, but after I used it, it produced the screen like this: A 2 backs bug

How can I let my app navigate back to the main view from the secondary view in a better way?

The code for the second view (first is just a NavigationLink pointing to the second):

import SwiftUI

struct GameView: View {
    
    
    @State private var questionCounter = 1
    
    @State var userAnswer = ""
    
    @State private var alertTitle = ""
    
    @State private var gameOver = false
    @State private var menuNavigation = false
    
    
    var body: some View {
        NavigationView{
            ZStack{
                NavigationLink(destination:ContentView(), isActive: $menuNavigation){
                    Text("")
                }
            VStack{
                
                Text("Give the answer")
                TextField("Give it", text: $userAnswer)
                
                Button("Submit", action: answerQuestion)
            }
            .alert(isPresented: $gameOver) {
                Alert(title: Text(alertTitle),
                      dismissButton: Alert.Button.default(
                        Text("Back to menu"), action: {
                            menuNavigation.toggle()
                        }
                      )
                )
                }
            }
            }
            
            }
    
    func answerQuestion() {
        
        questionCounter += 1
        
        if questionCounter == 2 {
            gameOver.toggle()
            alertTitle = "Game Over"
        
        }
        
    }
}

Thanks for your help :)


Solution

  • To achieve what you are expecting, you actually need to add the NavigationView inside ContentView, if that's your main view. Because you navigate from ContentView to GameView, and what you are asking here is how to navigate back.

    Applying the concept above, you can just dismiss GameView to go back to the in view.

    Here is a sample code to achieve that:

    Example of main view:

    struct ContentView: View {
        var body: some View {
            NavigationView {
                NavigationLink {
                    GameView()
                    
                        // This is how you hide the "<Back" button, so the user
                        // can navigate back only when tapping the alert
                        .navigationBarHidden(true)
                } label: {
                    Text("Go to game view")
                }
            }
        }
    }
    

    Example of game view:

    struct GameView: View {
        
        // This variable will dismiss the view
        @Environment(\.presentationMode) var presentationMode
        
        @State private var questionCounter = 1
        @State var userAnswer = ""
        @State private var alertTitle = ""
        @State private var gameOver = false
        
        // No need to use this variable
        // @State private var menuNavigation = false
        
        var body: some View {
            
            // No need to have a NavigationView
            // NavigationView {
            
                // ZStack has no function apparently...
                // ZStack{
            
                    // No need to have a NavigationLink
                    // NavigationLink(destination:ContentView(), isActive: $menuNavigation){
                    //    Text("")
                    //}
                VStack {
                    
                    Text("Give the answer")
                    TextField("Give it", text: $userAnswer)
                    
                    Button("Submit", action: answerQuestion)
                }
                .alert(isPresented: $gameOver) {
                    Alert(title: Text(alertTitle),
                          dismissButton: Alert.Button.default(
                            Text("Back to menu"), action: {
                                
                                // This is how you go back to ContentView
                                presentationMode.wrappedValue.dismiss()
                            }
                          )
                    )
            }
        }
        
        
        func answerQuestion() {
            
            questionCounter += 1
            
            if questionCounter == 2 {
                gameOver.toggle()
                alertTitle = "Game Over"
            }
        }
    }