I have tried apple example Bringing robust navigation structure to your SwiftUI app
so my code looks like this
NavigationSplitView(
columnVisibility: $navigationModel.columnVisibility
) {
List(
categories,
selection: $navigationModel.selectedCategory
) { category in
NavigationLink(category.localizedName, value: category)
}
.navigationTitle("Categories")
.toolbar {
ExperienceButton(isActive: $showExperiencePicker)
}
} detail: {
NavigationStack(path: $navigationModel.recipePath) {
RecipeGrid(category: navigationModel.selectedCategory)
}
}
Details View
struct RecipeGrid: View {
var category: Category?
var dataModel = DataModel.shared
var body: some View {
ZStack {
if let category = category {
ScrollView {
LazyVGrid(columns: columns) {
ForEach(dataModel.recipes(in: category)) { recipe in
NavigationLink(value: recipe) {
RecipeTile(recipe: recipe)
}
.buttonStyle(.plain)
}
}
.padding()
}
.navigationTitle(category.localizedName)
.navigationDestination(for: Recipe.self) { recipe in
RecipeDetail(recipe: recipe) { relatedRecipe in
NavigationLink(value: relatedRecipe) {
RecipeTile(recipe: relatedRecipe)
}
.buttonStyle(.plain)
}
}
} else {
Text("Choose a category")
.navigationTitle("")
}
}
}
var columns: [GridItem] {
[ GridItem(.adaptive(minimum: 240)) ]
}
}
My issue is if I go to details view then tap on other sidebar item after that return to same tap, it will return to rootview also onAppear it toggled! that mean the view did rebuild itself
on Apple News app it will stay on save view it won't rebuild or return to rootview when I change sidebar item
I want same behavior, but I don't know how can I do it
I didn't find any question here or any article explain how to do the same behavior as Apple News app
I think the solution is rather complex. I tried modifying the code myself but there’s quite a few things that need to change.
Firstly, the problem is caused because here
NavigationStack(path: $navigationModel.recipePath)
the recipePath gets reset every time the users taps the sidebar. I wish I understood why, but I passed to path a manual bindingBinding.init(get:set:)
.Secondly, the route is [Recipe], so when you select another category it makes sense that this route will be emptied. Otherwise, when the user taps the sidebar, the selected item from the previous category would still show.
So you would need the route to be a dictionary ([Category: [Recipe]]) and you need to hold the route for each category.
After I made this change, I saw in Apple Documentation that you can restore the route after the view has appeared, probably this solves the first problem.
So every time the category would change, I would make a copy of the route for that category. Then I tried to restore it when the category was tapped again, but I got stuck here because onAppear wasn’t triggered for me on
RecipeGrid(…).onAppear {}
.