NavigationView a Due Colonne per MacOS con SwiftUI

In una NavigationView a due colonne abbiamo una barra laterale, a sinistra, con un elenco di elementi (un menu) e una view di dettaglio. In questo esempio selezionando una voce del menu a sinistra verrà cambiata la view di dettaglio (la colonna di destra). Per memorizzare l’elemento selezionato utilizziamo una proprietà AppStorage

Creaimo un enum che contenga tutte le selezioni possibile, in questo esempio utilizzeremo alcuni sport


enum Sport: String, CaseIterable, Identifiable {
    case calcio
    case tennis
    case basket
    case rugby
    case hockey
    var id: String { rawValue }
}
         

Passiamo alla ContentView, dove inizializziamo una chiave "selezione"

@AppStorage("selezione") private var selezione: Sport = .calcio

Inseriamo una NavigationView contenente le due colonne, ovvero una Sidebar a sinistra e una DetailView a destra


NavigationView {
    Sidebar(selezione: Binding($selezione))
    DetailView(selezione: selezione)
    }
    .frame(width: 800, height: 400)

Nella Sidebar creiamo un Binding per la selezione

@Binding var selection: Sport?

E nella View elenchiamo tutti gli elementi dell' Enum Sport


List(Sport.allCases, id: \.self, selection: $selezione) { sport in
            Text(sport.rawValue)
        }
        .listStyle(SidebarListStyle())

Inseriamo il toggle per nascondere la Sidebar


.toolbar {
    Button(action: toggleSidebar, label: {
        Image(systemName: "sidebar.left").help("Toggle Sidebar")
    })
}

E la relativa funzione


private func toggleSidebar() {
    NSApp.keyWindow?.contentViewController?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
}
        

Nella View dettaglio mettiamo uno Switch per mostrare un testo diverso a seconda di quale sport viene scelto nella Sidebar


struct DetailView: View {

    var selezione: Sport

    var body: some View {
        switch selezione {
        case .calcio:
            Text("⚽️ \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        case .tennis:
            Text("🎾 \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        case .basket:
            Text("🏀 \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        case .rugby:
            Text("🏉 \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        case .hockey:
            Text("🏒 \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        }
    }
}

Di seguito il codice completo:

            
import SwiftUI

enum Sport: String, CaseIterable, Identifiable {
    case calcio
    case tennis
    case basket
    case rugby
    case hockey
    var id: String { rawValue }
}

struct Sidebar: View {

    @Binding var selezione: Sport?

    var body: some View {
        List(Sport.allCases, id: \.self, selection: $selezione) { sport in
            Text(sport.rawValue)
        }
        .listStyle(SidebarListStyle())
        .toolbar {
            Button(action: toggleSidebar, label: {
                Image(systemName: "sidebar.left").help("Toggle Sidebar")
            })
        }
        .frame(minWidth: 150)
    }
}

struct DetailView: View {

    var selezione: Sport

    var body: some View {
        switch selezione {
        case .calcio:
            Text("⚽️ \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        case .tennis:
            Text("🎾 \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        case .basket:
            Text("🏀 \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        case .rugby:
            Text("🏉 \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        case .hockey:
            Text("🏒 \(selezione.rawValue)").font(.title).frame(minWidth: 200)
        }
    }
}

private func toggleSidebar() {
    NSApp.keyWindow?.contentViewController?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
}

struct ContentView: View {
    @AppStorage("selezione") private var selezione: Sport = .calcio

    var body: some View {
        NavigationView {
                   Sidebar(selezione: Binding($selezione))
                   DetailView(selezione: selezione)
               }
               .frame(width: 800, height: 400)
    }
}

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

Potete trovare il codice completo su Github