In the Apple Music app on iPad (horizontal size class == .regular), when a selection is made from the Split View sidebar, the detail switches to a separate UINavigationController for that selection, where we can push/pop views. If we make a different selection from the sidebar, we get another UINavigationController to manipulate. If we return to the first selection, the detail view is still showing the stack contents for that controller.
I am trying to get the same behavior from NavigationSplitView in SwiftUI, but the detail view will reset its presented controller to its root. I think this is because NavigationSplitView uses whatever NavigationStack it finds in the detail hierarchy to manage its contents, effectively erasing the per-view stack contents. I have tried various methods of saving and restoring the navigation path without any luck. Any ideas on how to approach this?
I have included a very simple example to show what I'm talking about.
import SwiftUI
struct ExampleView: View {
enum Selection: String, CaseIterable {
case letters
case numbers
}
@State private var selection: Selection?
var body: some View {
NavigationSplitView {
List(selection: $selection) {
ForEach(Selection.allCases, id: \.self) { selection in
NavigationLink(value: selection) {
Text(selection.rawValue.capitalized)
}
}
}
.navigationTitle("Sidebar")
} detail: {
switch selection {
case .letters:
self.lettersView
case .numbers:
self.numbersView
default:
Text("Make a selection")
}
}
}
var lettersView = LettersView()
var numbersView = NumbersView()
}
struct ExampleView_Previews: PreviewProvider {
static var previews: some View {
ExampleView()
}
}
// MARK: -
struct LettersView: View {
private let letters = ["a", "b", "c", "d", "e", "f"]
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
List {
ForEach(letters, id: \.self) { letter in
NavigationLink(value: letter) {
Text(letter.uppercased())
}
}
}
.navigationTitle("Letters")
.navigationDestination(for: String.self) { letter in
Text(letter.uppercased()).font(.largeTitle)
}
}
}
}
// MARK: -
struct NumbersView: View {
private let numbers = Array(0..<6)
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
List {
ForEach(numbers, id: \.self) { number in
NavigationLink(value: number) {
Text(String(number))
}
}
}
.navigationTitle("Numbers")
.navigationDestination(for: Int.self) { number in
Text(String(number)).font(.largeTitle)
}
}
}
}