Search code examples
swiftswiftuiswiftui-navigationlinkswiftui-navigationview

SwiftUI: NavigationView in containers


SwiftUI beginner here. I've been stuck on this for the last 8 days or so. I've watched dozens of videos and searched for hours but cannot find the answer. I know that it's something very obvious and simple, but I can't figure it out.

I have a very large app, and I've replicated my issue below on the smallest scale that I can so that it is easier to understand. I get that the setup may seem illogical in some parts (mainly with the ForEach() use), but that's just a result of trying to represent my issue on a small scale. I have 3 files:

This file holds 3 buttons, which display a view (shown further down) when clicked. Key note: When the buttons are clicked, instead of the entire screen showing the destination view, only the button container shows the view.

ListOfButtonsView.swift

struct ListOfButtonsView: View {
    
    let buttonNames = ["Button 1", "Button 2", "Button 3"]
    
    var body: some View {
        
        VStack {
            ForEach(0..<buttonNames.count) { button in
                IndividualButtonView()
            }
        }
    }
}

This file holds the blueprint for each button in the previous file:

IndividualButtonView.swift

struct IndividualButtonView: View {
        
    var body: some View {
        
        NavigationView {
            NavigationLink(destination: CirclesView()) {
                VStack {
                    Text("Button")
                        .font(.largeTitle)
                        .padding(32)
                }
                .frame(maxWidth: .infinity)
                .foregroundColor(.white)
                .background(Color.red)
                .cornerRadius(12)
                .navigationBarHidden(true)
                .padding()
            }
        }
    }
}

Finally, the file that holds the view that I want the buttons to navigate to:

CirclesView.swift

struct CirclesView: View{
    var body: some View {
        VStack {
            Circle()
                .foregroundColor(.red)
            Circle()
                .foregroundColor(.green)
            Circle()
                .foregroundColor(.blue)
        }
        .navigationBarHidden(true)
    }
}

So, as mentioned before, when the buttons are clicked, only the button container shows the destination view. However, my desired result is for the entire screen to switch to the destination view (CirclesView.swift). How can I do this?

Any help is greatly appreciated!


Solution

  • Just move NavigationView out of IndividualButtonView and into ListOfButtonsView. It's ok to not have NavigationLink directly inside a NavigationView, as long as somewhere higher up in the hierarchy there was one.

    struct ListOfButtonsView: View {
        let buttonNames = ["Button 1", "Button 2", "Button 3"]
        var body: some View {
            NavigationView { /// here!
                VStack {
                    ForEach(0..<buttonNames.count) { button in
                        IndividualButtonView()
                    }
                }
            }
        }
    }
    
    struct IndividualButtonView: View {
        var body: some View { /// remove `NavigationView`
            NavigationLink(destination: CirclesView()) {
                VStack {
                    Text("Button")
                        .font(.largeTitle)
                        .padding(32)
                }
                .frame(maxWidth: .infinity)
                .foregroundColor(.white)
                .background(Color.red)
                .cornerRadius(12)
                .navigationBarHidden(true)
                .padding()
            }
        }
    }
    

    Result:

    Entire screen changes to `CirclesView`