Posts

Post not yet marked as solved
0 Replies
358 Views
I've run into two issues using NavigationSplitView with .navigationDestination modifiers. First, programmatic navigation using .navigationDestination(isPresented: destination) does not seem to work when used in the content column of a NavigationSplitView It does, however, work from the sidebar / first column. Second, it appears that we need to add redundant .navigationDestination modifiers on iPhone and iPad to handle how NavigationSplitView is adapted when used on iPhone. Specially, when it is collapsed into a NavigationStack. Also, when an iPad UI is collapsed to a NavigationStack via Stage Manager, then expanded again, .navigationDestination modifiers in the content column seem to get lost, preventing the content list from working going forward. This somewhat explains why dynamically adding .navigationDestinations via the first column push isn't sufficient. However it results in a broken UI. Is there one location we can place .navigationDestination modifiers to work both on iPad and iPhone? For example, technically, there is a .navigationDestination in the content column of the NavigationSplitView once one of the top level options are selected. However it's not at the top level. And the .navigationDestination isn't there by default. It's only "pushed" there at a later time. This makes sense, if you take into account the underlying adaptation implementation of NavigationSplitView under the hood, but the documentation doesn't seem to account for how the view hierarchy is adopted by the system. See this minimal reproduction... import SwiftUI enum SubSection: Hashable { case first case second case third var title: String { switch self { case .first: return "First" case .second: return "Second" case .third: return "Third" } } } struct ContentView: View { @State var showDetail: Bool = false @State var showList: Bool = false var body: some View { let _ = Self._printChanges() NavigationSplitView { List { NavigationLink(value: "A") { Text("Section A") } // This "pushes" to the content column Button { showList.toggle() } label: { HStack { Text("Section B") Spacer() Image(systemName: showList ? "checkmark.circle.fill" : "checkmark.circle") } } } .navigationDestination(for: String.self, destination: { value in ListView(sectionID: value, showDetail: $showDetail) }) .navigationDestination(isPresented: $showList) { ListView(sectionID: "B", showDetail: $showDetail) } .listStyle(.sidebar) .navigationTitle("Sidebar") } content: { Text("Default") // Destinations for iPad // We cannot use the destinations present in the ListView? // Must destinations be in the content column to push to // the detail column? .navigationDestination(for: SubSection.self, destination: { value in Text("Detail: \(value.title)") }) .navigationDestination(isPresented: $showDetail, destination: { Text("Detail: \(showDetail ? "true" : "false")") }) } detail: { Text("Detail") } .onChange(of: showDetail) { newValue in print("Show Detail: \(newValue)") } } } struct ListView: View { var sectionID: String @Binding var showDetail: Bool var body: some View { List { // This does *not* "push" to the detail column! Button { showDetail.toggle() } label: { HStack { Text("Toggle isPresented") Spacer() Image(systemName: showDetail ? "checkmark.circle.fill" : "checkmark.circle") } } NavigationLink(value: SubSection.first) { Text("\(SubSection.first.title)") } NavigationLink(value: SubSection.second) { Text("\(SubSection.second.title)") } NavigationLink(value: SubSection.third) { Text("\(SubSection.third.title)") } } .listStyle(.insetGrouped) .navigationTitle("Section: \(sectionID)") // Redundent destinations for iPhone as destinations in // the content column are not yet realized in the collaped // StackView representation of the NavigationSplitView? .navigationDestination(for: SubSection.self, destination: { value in Text("Detail: \(value.title)") }) .navigationDestination(isPresented: $showDetail, destination: { Text("Detail: \(showDetail ? "true" : "false")") }) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } From my comment below...
Posted Last updated
.