Variable 3-Column NavigationView SwiftUI

Viewed 440

Problem

I would like to be able to change the number of columns in a Navigation View depending on the sidebar selection. i.e. Most views will have the desired 3-column layout (sidebar > list > detail) but one will have a two column layout (sidebar > detail). I tried to set this up directly in the top layer of the navigation view but this didn't change anything.

NavigationView{
    SidebarView()
    if selection != .explore {
          ListView()
    }
    DetailView()
}

In the above example, if the selection is 'explore' there should only be a sidebar and a detail view.

Any ideas on how to achieve this?

Code to reproduce

I would want "searchView" to take up the full width. Meaning just a sidebar and search view should appear

Run on macOS or iPadOS

import SwiftUI

enum SidebarSelection {
    case library
    case notes
    case search
}


struct ContentView: View {
    
    @State var selection : SidebarSelection? = SidebarSelection.library
    
    var body: some View {
        NavigationView {
            List {
                NavigationLink(destination: ListView(), tag: SidebarSelection.library, selection: $selection){
                    Label("Library", systemImage: "book")
                }
                .tag(SidebarSelection.library)
                NavigationLink(destination: ListView(), tag: SidebarSelection.notes, selection: $selection){
                    Label("Notes", systemImage: "doc.text")
                }
                .tag(SidebarSelection.notes)
                NavigationLink(destination: SearchView(), tag: SidebarSelection.search, selection: $selection){
                    Label("Search", systemImage: "magnifyingglass")
                }
                .tag(SidebarSelection.search)
            }
            .listStyle(SidebarListStyle())
            
            Text("List View")
            
            if selection != .search {
                Text("Detail View")
            }
        }
    }
}

struct ListView: View {
    var body: some View{
        List {
            ForEach(0..<10){ index in
                NavigationLink(destination: Text("DetailView: \(index)")){
                    Text("Link to \(index) detail view")
                }
            }
        }
    }
}

struct SearchView: View {
    var body: some View {
        Text("Full width search view")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
1 Answers

What you can do is quite easy actually, to achieve this, you just have to be bit more specific for SwiftUI and use the @ViewBuilder property wrapper.

struct ContentView: View {
    
    @ViewBuilder
    var body: some View {
        if(twoColumns == true){
            NavigationView{
                SidebarView()
                DetailView()
            }
        } else {
            NavigationView{
                SidebarView()
                ListView()
                DetailView()
            }
        }
    }
}
Related