Есть ли у кого-нибудь работающий NavigationSplitView с NavigationStack в подробном представлении?
Независимо от того, как он настроен, сложный трехколоночный NavigationSplitView с NavigationStack дает сбой или имеет противоречивый рабочий процесс.
Выбор боковой панели определяет, какой контент (или функция) находится в разделе «Контент».
Контент (или функция), который доступен (или выбран), может контролировать детали.
Подробности должны быть Navigable, а NavigationDestinations зависят от каждой функции (выбранного контента), поэтому их нельзя зарегистрировать все под одним корнем.
Варианты, которые я пробовал: (и многие другие)
@State var sideBar: SideBar?
@State var content: Content?
NavigationSplitView(
sidebar: {
List(sidebar) { ... }
},
content: {
switch sidebar { ... }
},
detail: {
XXX what to put here?
}
).navigationSplitViewStyle(.balanced)
Каждая боковая панель содержит набор маршрутов, который зависит от нее. Итак, подробно: я пробовал несколько вариантов.
// this does not work as NavigationStack is not simple
// enough to be completely removed or recreated
// somehow it ties on the Scene and crashes when
// switching between sidebars
detail: {
switch sidebar {
case .a:
NavigationStack {
View()
.navigationDestination(...
}
}
}
// clearing the navigationPath just before switching
// sidebars, but still controlling a NavigationStack
// inside details does not work, nothing happens.
detail: {
switch sidebar {
case .a:
NavigationStack(navigationPath) {
View()
.navigationDestination(...
}
}
}
// Having an empty NavigationStack in details
// but registering the destinations inside the content.
// This works however, when switching between sidebar
// it also crashes sometimes or it shows the Warning triangle
// on the navigation stack, as destinations become unavailable.
content: {
switch sidebar {
case .a:
RootView()
.navigationDestination(...)
}
},
detail: {
NavigationStack { }
}
// Trying to clear out the path before switching
// does not work either.
content: {
switch sidebar {
case .a:
RootView()
.navigationDestination(...)
}
},
detail: {
NavigationStack(navigationPath) { }
}
1 ответ
После долгих отладок я нашел способ, который работает.
Размещение одного NavigationStack в представлении Details и сохранение где-нибудь NavigationPath. При переключении между боковой панелью мне пришлось очистить путь, прежде чем разрешить NavigationSplitView обновить себя и свое содержимое.
Мне также пришлось установить определенный .id() для представления содержимого, которое является боковой панелью, каким-то образом, даже когда боковая панель изменяется, содержимое не обновляется.
Я тестировал это на iPhone 16.4, iPad и MacOs.
// in StateObject, Model or wherever
var selectedSidebar: SomeSidebarType? {
willSet {
if navigationPath.isEmpty {
// if the stack is empty, we do not need to clear it
objectWillChange.send()
} else {
// otherwise clear it, and do not send an update
// as the stack will update the view and itself
stack.removeLast(stack.count)
}
}
}
@ViewBuilder
var detail: some View {
NavigationStack(path: $storage.navigationPath) {
switch storage.selectedSidebar {
case .a:
SomeView
case .b:
SomeView
default:
Text("No Selection")
}
}
}