The SwiftUI cookbook for navigation

RSS for tag

Discuss the WWDC22 Session The SwiftUI cookbook for navigation

Posts under wwdc2022-10054 tag

11 Posts
Sort by:
Post not yet marked as solved
1 Replies
75 Views
It looks like passing a binding (instead of value) to a detail view is not possible with NavigationSplitView. For example, how to adopt NavigationSplitView in sample app Date Planner — Sample Apps Tutorials | Apple Developer Documentation does not seem straight forward. The only way seems to be to use ObservableObjects and use separate update methods on data. ...     ForEach(eventData.sortedEvents(period: period)) { $event in         NavigationLink {             EventEditor(event: $event)         } label: {             EventRow(event: event)         }
Posted
by nkalvi.
Last updated
.
Post not yet marked as solved
0 Replies
52 Views
Is there any convenient way to back deploy the NavigationStack or NavigationSplitView?? The real problem is if I want to back support iOS 15 or 14, I must conditionally switch between NavigationView and NavigationStack / NavigationSplitView. Here is how I did for NavigationStack, but I have no idea how to deal with NavigationSplitView import SwiftUI struct NavigationStack<Content: View>: View {     var content: () -> Content     var body: some View {         if #available(iOS 16.0, macOS 13.0, *) {             SwiftUI.NavigationStack {                 content()             }         } else {             NavigationView {                 content()             }.navigationViewStyle(.stack)         }     } } Will the new NavigationStack and NavigationSplitView back support old devices? I think these behaviors in previous OS is not new features.
Posted Last updated
.
Post not yet marked as solved
3 Replies
192 Views
Hello, On the recent iOS / iPadOS 16, SwiftUI 4, and Xcode Version 14.0 beta (14A5228q), my app contains a NavigationStack within the content view; and the stack contains a ForEach that iterates over a list of fruits / items. The form loop outputs a navigation link, the label being a view, and the destination being another NavigationStack. And whenever I go to click on that link, the app shoots me back to the root view instantly. This seems to happen whenever I have any kind of content in the StackNavigation that's within the NavigationLink. I will post the code snippets below, along with a GIF showing the bug in action. ContentView.Swift: struct ContentView: View {     @State private var isShowingSettings: Bool = false     var fruits: [Fruit] = fruitsData     var body: some View {         NavigationStack {             List(fruits.shuffled()) { fruit in                 NavigationLink(destination: FruitDetailView(fruit: fruit)) {                     FruitRowView(fruit: fruit) .padding(.vertical, 4)                 }             }             .navigationBarTitle("Fruits")             .toolbar {                 ToolbarItem(placement: .navigationBarTrailing) {                     Button(action: {                         isShowingSettings = true                     }) {                         Image(systemName: "slider.horizontal.3")                     }                     .sheet(isPresented: $isShowingSettings) {                         SettingsView()                     }                 }             }         }     } } FruitDetailView.Swift: // Code is shortened, but has the same bug as the actual code struct FruitDetailView: View {     var fruit: Fruit     var body: some View {         NavigationStack {             ScrollView(.vertical, showsIndicators: false) { Text(fruit.name)             }             .edgesIgnoringSafeArea(.top)         }     } Preview:
Posted Last updated
.
Post not yet marked as solved
1 Replies
109 Views
Context I have a problem with the new SwiftUI SideBar / NavigationLink concept. I have created a simple 2 Column NavigationSplitView with a SideBar and a DetailView. Once the App is launched, the preselected Timeline RootView appears as the DetailView. However, when I select a different SideBar Item, the DetailView does not change accordingly. Code struct SideBar: View { @State private var navigationItem: NavigationItem? = .timeline var body: some View { NavigationSplitView { List(NavigationItem.allCases, id: \.self, selection: $navigationItem) { navigationItem in NavigationLink(value: navigationItem) { Label(navigationItem.name, systemImage: navigationItem.symbol) } } } detail: { if let safeNavigationItem = navigationItem { safeNavigationItem.rootView } else { Text(String(localized: "select.an.option", defaultValue: "Select an Option")) } } } } Question Do you have any idea how I can solve this issue? Thanks a lot for your support in advance. Note: Just ran it on macOS, it is working there. However, still not working on iPadOS.
Posted Last updated
.
Post marked as solved
4 Replies
1.3k Views
Overview: When running the demo code presented in "The SwiftUI cookbook for navigation" (https://developer.apple.com/wwdc22/10054) I ran into some issues: Runtime warnings: 2022-06-08 22:20:31.587169+0800 NavigationSplitViewDemo[17797:672165] [SwiftUI] A NavigationLink is presenting a value of type “Category” but there is no matching navigation destination visible from the location of the link. The link cannot be activated. onChange(of: UpdateTrigger) action tried to update multiple times per frame. 2022-06-08 22:15:23.432289+0800 NavigationSplitViewDemo[17645:662571] [UIFocus] _TtGC7SwiftUI14_UIHostingViewGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen. Feedback filed: FB10103041 and FB10104196
Posted
by newwbee.
Last updated
.
Post not yet marked as solved
3 Replies
305 Views
Hi there, I'm struggling with the new NavigationSplitView. struct Team: Identifiable, Hashable {     let id = UUID()     var name: String     var players: [String] } struct SplitView3: View {     @State private var teams = [ Team(name: "Packers", players: ["Rodgers", "Alexander", "Dillon"]), Team(name: "Vikings", players: ["Ingram", "Cousins", "Berry"])     ]     @State private var selectedTeam: Team?     @State private var selectedPlayer: String?         var body: some View {             NavigationSplitView {                 List(teams, selection: $selectedTeam) { team in                     Text(team.name).tag(team).navigationTitle("Team")                 }.navigationBarHidden(true)                 .navigationSplitViewColumnWidth(250)             } content: {                 List(selectedTeam?.players ?? [], id: \.self, selection: $selectedPlayer) { player in                     Text(player).navigationTitle("Team Member")                 }             } detail: {                 Form{                     Text(selectedPlayer ?? "Choose a player.")                 }                 .navigationTitle("Player Detail").navigationBarTitleDisplayMode(.inline)             }             .navigationSplitViewStyle(.automatic)         } } When I run this in Simulator or Canvas I can navigate from Team (sidebar), trough Teammembers (content) to detail view and back to sidebar. But after I reach the sidebar again the links forward to content view don't work anymore. Did I miss something?
Posted Last updated
.
Post not yet marked as solved
2 Replies
179 Views
The new NavigationSplitView is very handy. I want to use it for a settings screen, but I need a way to navigate in and out of it. Previously I just navigated in and out of my settings using a NavigationView. But if I change this to a NavigationStack, and then navigate forward into a NavigationSplitView from it, it almost works fine, but some weirdness happens: on iPhone there are two competing back arrows (i.e "<") and on an iPad there is weird spacing at the top of the screen. Should I be able to navigate from a NavigationStack into a NavigationSplit View? If so, are these known issues? If not, is there a recommended UI for navigating in and out of a NavigationSplitView from the rest of my iPhone/iPad app? thanks!
Posted
by breville.
Last updated
.
Post not yet marked as solved
3 Replies
317 Views
Is it possible to drive NavigationSplitView navigation with a view in sidebar (left column) that is not a List? All examples that I have seen from this year only contain List in sidebar. I ask this because I would like to have a more complex layout in sidebar (or first view on iOS) that contains a mix of elements, some of them non-interactive and not targeting navigation. Here’s what I would like to do: import SwiftUI struct Thing: Identifiable, Hashable {     let id: UUID     let name: String } struct ContentView: View {     let things: [Thing]     @State private var selectedThingId: UUID?          var body: some View {         NavigationSplitView {             ScrollView(.vertical) {                 VStack {                     ForEach(things) { thing in                         Button("Thing: \(thing.name) \( selectedThingId == thing.id ? "selected" : "" )") {                             selectedThingId = thing.id                         }                     } SomeOtherViewHere() Button("Navigate to something else") { selectedThingId = someSpecificId }                 }             }         } detail: {             // ZStack is workaround for known SDK bug             ZStack {                 if let selectedThingId {                     Text("There is a thing ID: \(selectedThingId)")                 } else {                     Text("There is no thing.")                 }             }         }     } } This actually works as expected on iPadOS and macOS, but not iOS (iPhone). Tapping changes the selection as I see in the button label, but does not push anything to navigation stack, I remain stuck at home screen. Also filed as FB10332749.
Posted
by Jaanus.
Last updated
.
Post not yet marked as solved
0 Replies
113 Views
I'm trying to manage state restoration in our application. I failed to get NavigationView/NavigationLink working in pre-iOS 16 SwiftUI. I'm now trying to get it working with NavigationStack/NavigationLink/navigationDestination with iOS 16. I've built a sample application that demonstrates the issue: import SwiftUI @main struct PushMultipleViews7App: App {     var body: some Scene {         WindowGroup {             ContentView()         }     } } enum Route: Hashable, Codable {     case view1     case view2     case view3     case view4 } struct ContentView: View {     @State     private var navigationPath: [Route]     @Environment(\.scenePhase)     private var scenePhase     init() {         guard let data = UserDefaults                   .standard                   .data(                       forKey: "NavigationPath"                   ),               let navigationPath = try? JSONDecoder()                   .decode(                       [Route].self,                       from: data                   )         else {             self._navigationPath = State(                 initialValue: []             )             print("Failed to read NavigationPath")             return         }         print("Read:",navigationPath)         self._navigationPath = State(             initialValue: navigationPath         )     }     var body: some View {         VStack {             NavigationStack(                 path: $navigationPath             )             {                 View1()                     .navigationDestination(                         for: Route.self                     )                 { route in                     switch route {                     case .view1:                         View1()                     case .view2:                         View2()                     case .view3:                         View3()                     case .view4:                         View4()                     }                 }             }         }             .onChange(                 of: scenePhase             )             { scenePhase in                 guard case .inactive = scenePhase                 else {                     return                 }                 guard let data = try? JSONEncoder()                           .encode(                               navigationPath                           )                 else {                     print("Failed to write NavigationPath")                     return                 }                 print("Writing:",navigationPath)                 UserDefaults                     .standard                     .setValue(                         data,                         forKey: "NavigationPath"                     )             }     } } struct View1: View {     var body: some View {         VStack {             Text("Hello View1!")             NavigationLink(                 value: Route.view2,                 label: {                     Text("Navigate to View2")                 }             )         }             .navigationTitle("View 1")     } } struct View2: View {     var body: some View {         VStack {             Text("Hello View2!")             NavigationLink(                 value: Route.view3,                 label: {                     Text("Navigate to View3")                 }             )         }             .navigationTitle("View 2")     } } struct View3: View {     var body: some View {         VStack {             Text("Hello View3!")             NavigationLink(                 value: Route.view4,                 label: {                     Text("Navigate to View4")                 }             )         }             .navigationTitle("View 3")     } } struct View4: View {     var body: some View {         Text("Hello, View4!")     } }``` To replicate the issue: from Xcode 14, run the app above in your favorite iOS 16 phone simulator. Tap on the NavigationLinks to navigate to View 4. Navigate to the Home Screen (put the app into the background). Wait a few seconds for UserDefaults to catch up. "Swipe up" to kill the app. Relaunch the app. View4 should be displaying...which is the expected behavior. Tap the "View 3" button (the "back" button) to display View3. As before, navigate to the Home Screen, wait a few seconds then "swipe up" to kill the app. Relaunch the app. Instead of displaying "View3", the app should be displaying View1. Evidence can be seen in the console when writing the navigation path to UserDefaults - it wrote "[]". That's just one variation among lots of strange behavior I've seen trying to restore a NavigationStack's navigation path. I've filed: FB10398702 I've tried several variations of this application: using @AppStorage and @SceneStorage instead of UserDefaults. I've also tried the sample code accompanying NavigationPath in Apple's documentation (though also based on UserDefaults). Am I doing something incorrectly or is this a bug? Thanks, --David
Posted
by djehrlich.
Last updated
.
Post not yet marked as solved
1 Replies
188 Views
Is there a way to clear/reset the detail view when the user selects a new item in the sidebar but hasn't yet selected an item from the content panel? Playing around with the WWDC22 demo project "Navigation Cookbook", I noticed that if you select a Category, then a Recipe, the recipe details display as expected. If you then select a new category, though, the original recipe remains in the detail panel until you select a new recipe. I'd like the detail panel to reset to its original state of "Pick a Recipe".
Posted
by tharris.
Last updated
.
Post not yet marked as solved
1 Replies
202 Views
In a triple-column split view, it's common to hide the primary view when the user selects an item from a list. In some cases, the supplemental view is also hidden when an item is selected from that list, thus leaving only the detail view visible. What is the correct way to hide the primary view on selection and then to optionally hide the supplemental view on selection using the new NavigationStack? (Notes is a good example of the sidebars hiding after the user selects a folder in the sidebar.)
Posted
by kennyc.
Last updated
.