Still playing with the NavigationSplitView, but found no solution for the following.
I need/want to use here the .navigationDestination(for: .....) modifier and I want to call the different DetailViews with a switch but I can't get it to work.
What is wrong? Did I miss something here?
Data and Structs
import Foundation
import SwiftUI
struct Item1: Identifiable, Hashable {
var id = UUID()
var name: String
var place: String
var date: Date
}
struct Item2: Identifiable, Hashable {
var id = UUID()
var name: String
var place: String
var birthdate: Date
}
struct Item3: Identifiable, Hashable {
var id = UUID()
var name: String
var city: String
var dDay: Date
}
// Create some sample data
let items1 = [
Item1(name: "Alice", place: "Wonderland", date: Date()),
Item1(name: "Bob", place: "Bikini Bottom", date: Date()),
Item1(name: "Charlie", place: "Chocolate Factory", date: Date()),
Item1(name: "David", place: "Dungeon", date: Date()),
]
let items2 = [
Item2(name: "Alice", place: "Wonderland", birthdate: Date()),
Item2(name: "Bob", place: "Bikini Bottom", birthdate: Date()),
Item2(name: "Charlie", place: "Chocolate Factory", birthdate: Date()),
Item2(name: "David", place: "Dungeon", birthdate: Date()),
]
let items3 = [
Item3(name: "Alice", city: "Wonderland", dDay: Date()),
Item3(name: "Frank", city: "France", dDay: Date()),
Item3(name: "Harry", city: "Hogwarts", dDay: Date()),
Item3(name: "Iris", city: "Italy", dDay: Date()),
Item3(name: "Jack", city: "Japan", dDay: Date())
]
Define the views for the detail area
struct DetailView1: View {
var item: Item1
var body: some View {
VStack {
Text ("DetailView1")
Text(item.name)
.font(.largeTitle)
Text(item.place)
.font(.title)
Text(item.date, style: .date)
.font(.title2)
}
}
}
struct DetailView2: View {
var item: Item2
var body: some View {
VStack {
Text ("DetailView2")
Text(item.name)
.font(.largeTitle)
Text(item.place)
.font(.title)
Text(item.birthdate, style: .date)
.font(.title2)
}
}
}
struct DetailView3: View {
var item: Item3
var body: some View {
VStack {
Text ("DetailView3")
Text(item.name)
.font(.largeTitle)
Text(item.city)
.font(.title)
Text(item.dDay, style: .date)
.font(.title2)
}
}
}
MyNavigationView description
struct MyNavigationView: View {
let section1 = items1
let section2 = items2
let section3 = items3
// Use a state variable to store the selected item
@State var selectedItem: AnyView? // Item?
var body: some View {
NavigationSplitView {
List {
Section(header: Text("Section 1")) {
ForEach(section1) { item in
// Use the new NavigationLink with value and label
NavigationLink(value: item, label: {
Text(item.name)
})
}
}
Section(header: Text("Section 2")) {
ForEach(section2) { item in
// Use the new NavigationLink with value and label
NavigationLink(value: item, label: {
Text(item.name)
})
}
}
Section(header: Text("Section 3")) {
ForEach(section3) { item in
// Use the new NavigationLink with value and label
NavigationLink(value: item, label: {
Text(item.name)
})
}
}
}
.listStyle(SidebarListStyle())
.navigationDestination(for: AnyView) { viewType in
switch viewType {
case let viewType as DetailView1:
DetailView1($selectedItem)
.navigationTitle("Detail View1")
case let viewType as DetailView2:
DetailView2($selectedItem)
.navigationTitle("Detail View2")
case let viewType as DetailView3:
DetailView3($selectedItem)
.navigationTitle("Detail View3")
default:
EmptyView()
.navigationTitle("No Detail View")
}
}
} detail: {
Text("Select an item ")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
How can I select the right DetailView to show up in the detail view? When I use I get the error that AnyView is not Hashable. How can I solve this to understand what direction I should go?
First, the list selection should not have type
AnyView. The list selection should be some data that represents what is being selected, not a view. That said, you don't need this selection - since you are not driving theNavigationSplitViewwith a list, but withnavigationDestinations.Secondly, the types you pass to
navigationDestination(for:destination:)should be the types of your data. It should be the same type as the values you passed toNavigationLink(value:label:).Since you have 3 types of items, you should apply this three times:
Thirdly, the detail view of the split view is already determined by
navigationDestinations above. You can't have a separate view indetail:whenselection != nil. Just handle the case whenselection == nil:Alternatively, you can use a list selection type like this:
This is basically a way to have a single selection type for all 3 kinds of items. You would need to wrap the
ItemNs into this type when creating the navigation links. Other than that, it's the same as aList-driven navigation split view: