In the Food Truck app Apple Food Truck App the contentView has a NavigationSplitView to target iPadOS.
NavigationSplitView {
Sidebar(selection: $selection)
} detail: {
NavigationStack(path: $path) {
DetailColumn(selection: $selection, model: model)
}
}
...
I would like to change this to remove the navigationSplitView so that it targets iOS only. Something like this:
NavigationStack(path: $path) {
Sidebar(selection: $selection)
.navigationDestination(for: Panel.self) { panel in
DetailColumn(selection: $selection, model: model)
}
}
...
There are a couple of problems with this - the first problem is no navigation occurs. This is fixed by removing the $selection in Sidecar(). The second problem is that when the app does navigate, it only navigates to ".truck". To fix this, I have to go into DetailColumn and change selection to @State and change the above code to:
NavigationStack(path: $path) {
Sidebar(selection: $selection)
.navigationDestination(for: Panel.self) { panel in
DetailColumn(selection: panel, model: model)
}
}
...
Even though this works, Xcode does complain that "A navigationDestination for “Food_Truck.Panel” was declared earlier on the stack. Only the destination declared closest to the root view of the stack will be used."
I think I am missing some understanding of how this should be approached, or the design of the app was done so that it works with NavigationSplitView and not NavigationStackView directly.
Thanks in advance.
I don't quite follow the changes you made, but I've made similar changes and the app works.
First, remove the selection in Sidebar
. Sidebar
should no longer have a selection
property. You should just use the parameterless List
initialiser.
struct Sidebar: View {
var body: some View {
List {
NavigationLink(value: Panel.truck) {
Label("Truck", systemImage: "box.truck")
}
NavigationLink(value: Panel.orders) {
Label("Orders", systemImage: "shippingbox")
}
...
Then you can even get rid of the selection
state in ContentView
.
Next, selection
in DetailColumn
need not be a Binding
anymore. It is merely used to determine which detail view to show, and DetailColumn
doesn't change it at all, so it can be a let
.
struct DetailColumn: View {
let selection: Panel?
@ObservedObject var model: FoodTruckModel
@State var timeframe: Timeframe = .today
var body: some View {
switch selection ?? .truck {
case .truck:
TruckView(model: model) // TruckView no longer needs to take the selection
...
Note that TruckView
doesn't need to take a $selection
binding. TruckView
only uses it in the cardNavigation
computed property. This property just decides how navigation should be done. Notice that on iPhones, this always returns .navigationLink
. So you can just change it to:
var cardNavigation: TruckCardHeaderNavigation {
.navigationLink
}
and remove @Binding var navigationSelection: Panel?
.
Finally, the code in ContentView
looks like this:
NavigationStack(path: $path) {
Sidebar()
.navigationDestination(for: Panel.self) { panel in
DetailColumn(selection: panel, model: model)
}
}