The SwiftUI cookbook for navigation

RSS for tag

Discuss the WWDC22 Session The SwiftUI cookbook for navigation

Posts under wwdc2022-10054 tag

45 Posts

Post

Replies

Boosts

Views

Activity

Driving NavigationSplitView with something other than List?
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.
14
5
7.3k
Feb ’26
NavigationSplitView hide sidebar toggle button
I'm trying to implement the same UI used by the Settings app on iPad: a split view with two columns that are visible at all times. This code produces the layout i want, but I would like to hide the "toggle sidebar visibility" button that the system introduces. Is there a SwiftUI API I can use to hide this button? Maybe an alternate way to setup views that tells the system that the button is not necessary? struct SomeView: View { var body: some View { NavigationSplitView( columnVisibility: .constant(.all), sidebar: { Text("sidebar") }, detail: { Text("detail") } ) .navigationSplitViewStyle(.balanced) } }
7
3
8.6k
Mar ’25
SwiftUI NavigationLink freezing when tapped
Any one getting any issues with NavigaitonLink to seemingly innocuous views freezing when tapped on? 1 CPU at 100% memory steadily increasing until app gets killed by the system. Will freeze if any NavigationLink on the view is tapped if certain views are linked to using NavigaitonLink. I note some people have been getting similar freezes if they use @AppStorage, but I'm not using @AppStorage. I do use CoreData tho. tho I have some views that use core data that don't freeze. https://developer.apple.com/forums/thread/708592?page=1#736374022 has anyone experienced similar issues? or know the cause. it doesn't seem to be any of my code because if I pause the debugger it stops on system code.
18
2
11k
Nov ’24
Toolbar Menu button seems to look disabled
Overview On macOS, in a NavigationSplitView when the menu button is added to the detail view toolbar, it seems to look disabled Environment Xcode: 14.1 beta 3 (14B5033e) macOS: 13.0 Beta (22A5365d) Code: struct ContentView: View { @State private var selectedNumber: Int? var body: some View { NavigationSplitView { List(0..<100, selection: $selectedNumber) { number in Text("cell \(number)") } } detail: { Text("Detail") .toolbar { ToolbarItem { Menu { Button("aa") {} Button("bb") {} } label: { Label("Add Bookmark", systemImage: "book") } } } } } } Steps to reproduce: Run the project on macOS Select cell 0 on the sidebar Click on the book toolbar button and notice the menu appear Select cell 1 on the sidebar Expected Behaviour After step 4, the book toolbar button should look prominent (like it is enabled) Actual Behaviour After step 4, the book toolbar button looks like it is disabled. Screenshot
1
1
1.7k
Nov ’23
Embedding a NavigationStack within the detail view of a NavigationSplitView
I'm using a two column NavigationSplitView, where the view passed for the detail column is the root of a NavigationStack. The navigation works as expected, but the navigationTitle and toolbar elements of the detail view are very slightly delayed when the view appears on iOS, such that they 'pop' in rather than smoothly animating like normal. Returning to the root of the view from views higher in this stack animates as expected. Has anyone seen anything like this before? Thanks!
6
0
2.4k
Oct ’23
NavigationSplitView two and three column interfaces in the same app
I am currently learning to create multiplatform applications using SwiftUI and NavigationSplitView, and I faced the problem of arranging different Views in the same App. Let's open the default Notes application, and here, we can see a switch between two and three-column views of the content. So my question is, how to arrange this kind of view for different App pages using NavigationSplitView? First page has two columns interface Second has three columns
3
0
4k
Aug ’23
NavigationStack not working correctly in sheet
I am currently trying to build a NavigationManager with programmatic navigation. For that I'm using the NavigationPath combined with NavigationDestination. Sadly facing the following issue: navigationDestionation is not being recognised when located in sheet. Im receiving the following message when trying to update the path of the NavigationStack within the sheet. A NavigationLink is presenting a value of type “PathType” but there is no matching navigationDestination declaration visible from the location of the link. The link cannot be activated. Note: Links search for destinations in any surrounding NavigationStack, then within the same column of a NavigationSplitView. Here is some simplified code snipped of the implementation. struct RootView: View { @State private var isPresented: Bool = true var body: some View { Button("Open Modal", action: { self.isPresented.toggle() }) .sheet(isPresented: self.$isPresented, content: { ModalContent() }) } } private struct ModalContent: View { @State private var path = NavigationPath([PathType.configuration]) var body: some View { NavigationStack(path: self.$path) { VStack { Text("Placeholder") } .navigationDestination(for: PathType.self) { pathType in switch pathType { case .configuration: Text("Configuration") default: Color.red } } } } }
1
1
2.2k
May ’23
Selection state is lost when navigating to/from home screen
Hi! When using the Sample "NavigationCookbook" in the two column layout, the selection in the first column is not remembered, when navigating to the Home Screen and back. This behaviour can be reproduced by starting the app on the iPad or simulator, selecting for example "Pancake" and then navigating to the home screen and back into the navigation. Sometimes this (the navigation to/back from the home screen) has to be done twice, to lose the selection. In the console log you can see the message "Update NavigationAuthority bound path tried to update multiple times per frame." appearing. Not sure if this has something todo with the selection being lost. This is on iOS 16.4.1 not sure if the behaviour before was different. Anybody experiences the same behaviour? Bug in SwiftUI or in the sample app? Cheers, Michael
2
1
1.1k
Apr ’23
Getting Large Titles on WatchOS with a Navigation Stack
On my Watch app pre-WatchOS 9 I had code as follows: ` TabView { NavigationView { TodayView(model: delegate.model) .navigationBarTitleDisplayMode(.large) } NavigationView { SettingsView(model: delegate.model) } } .tabViewStyle(.page) However, for WatchOS 9 I'm using the new NavigationStack like this: ` NavigationStack { TabView { TodayView(model: delegate.model) .navigationBarTitleDisplayMode(.large) The issue is, with WatchOS 9 the title always displays as .inline and never large. I've tried embedding a list or scroll view. I've also tried placing a navigationView within the NavigationStack and TabView, that just makes duplicate titles. So, using the NavigationStack with a TabView on WatchOS 9, how do you get large titles? Thanks
3
0
1.8k
Mar ’23
Why is my navigationPath not reaching views further along my stack?
I've implemented a navigation stack that appends the next view's view model so that the appending and .navigationDestination looks like the below. Whenever I press the continue button to add the viewModel to the path in the ContentView (the child of BumperScreen and the second in the path), the app just stops. I tried isolating the problem with a test project using the same methodology for navigation and have been able to navigate several views, almost infinitely. I cannot replicate this issue and am having a hard time understanding why one is working, and not the other. struct BumperScreen: View { @State private var path = NavigationPath() @StateObject var viewModel: BumperScreenViewModel @StateObject var sheetManager = SheetManager() init(viewModel: @autoclosure @escaping () -> BumperScreenViewModel) { self._viewModel = .init(wrappedValue: viewModel()) } var body: some View { if isDoneOnboarding { HomeView() .environmentObject(sheetManager) } else { NavigationStack(path: $path) { ZStack { Color(.Gold) .ignoresSafeArea() VStack { if show { Spacer() loadAnimation .frame(width: 150, height: 150) .task { try? await viewModel.getDataFromAPI() try? await Task.sleep(for: Duration.seconds(1)) path.append(ContentViewViewModel()) doneLoading.toggle() show.toggle() } Spacer() } else if doneLoading { EmptyView() } else { launchAnimation } } .navigationDestination(for: ContentViewViewModel.self) { model in ContentView(viewModel: model, path: $path) .environmentObject(sheetManager) } } } } } } Which leads the user to the second view struct ContentView: View { @EnvironmentObject var sheetManager: SheetManager @StateObject var viewModel: ContentViewViewModel @Binding var path: NavigationPath var body: some View { ZStack { Color(.trulliGold) .ignoresSafeArea() VStack { Spacer() headerStatement Spacer() VStack { privacyPolicy bluetoothPolicy locationsPolicy notificationsPolicy apprunningPolicy } Spacer() Spacer() continueButton } } .popup(with: sheetManager) .navigationBarBackButtonHidden() } var continueButton: some View { Button(action: { print("pressed") path.append(WelcomeScreenViewViewModel()) }) { Text("CONTINUE") } .navigationDestination(for: WelcomeScreenViewViewModel.self) { model in WelcomeScreenView(viewModel: model, path: $path) } } } Which goes to struct WelcomeScreenView: View { @StateObject var viewModel: WelcomeScreenViewViewModel @Binding var path: NavigationPath var body: some View { ZStack { Color(.trulliGold) .ignoresSafeArea() VStack(alignment: .center, spacing: 8) { header Spacer() tabView Spacer() Spacer() nextButton closeButton } } .navigationDestination(for: SetupGuideSpeakerSearchViewViewModel.self) { model in SetupGuideSpeakerSearchView(viewModel: model, path: $path ) } .navigationBarBackButtonHidden() } } I've tried isolating the issue to a debug project and have been able to navigate several views therein with no issue. debug project
0
0
1.4k
Mar ’23
What is the best way for other ViewModel to get a reference to NavigationModel according to WWDC example?
In https://developer.apple.com/wwdc22/10054 it is shown that the best way to organize an iPad layout is by: struct TwoColumnContentView: View { @Binding var showExperiencePicker: Bool @EnvironmentObject private var navigationModel: NavigationModel var categories = Category.allCases var dataModel = DataModel.shared var body: some View { 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) } } } } NavigationModel defined as final class NavigationModel: ObservableObject, Codable { @Published var selectedCategory: Category? @Published var recipePath: [Recipe] @Published var columnVisibility: NavigationSplitViewVisibility } But what happens when in a child view, it triggers off some action in some other ViewModel that needs to update the navigation stack? struct ChildViewModel { func childViewCalledAndDidSomething { //now I need to update recipePath, how? } }
0
0
826
Mar ’23
Right Approach to test SwiftUI Views
How do we test SwiftUI views? Can we test them in Unit testing? If so we don't have proper apis to get the view hierarchy or the required set of objects for testing. We have to rely on using identifier for every object and extract the view with the id? I have seen many using ViewInspector which extracts the view hierarchy and has apis to test the array of views matching a text etc. But is it using a right approach for extracting views will it have issues when ever the Xcode or Os is upgraded? Is snapshot testing right approach for swiftUI views?
1
0
3.1k
Mar ’23
Hide & Disable TabBar when in NavigationDestination Subview - Apple Watch
I'm trying to create a UI layout and navigation functionality similar to the Apple Fitness app on Apple Watch. This is all WatchOS 9 so no need for older API support, phew! I want to have NavigationTitle set for each view in a TabBar. I want each selected NavigationDestination to hide the TabBar controls and disable swiping when opened. I want the NavigationTitle and update to remain whilst navigating between Tabs and Childs. I've created this sample code based off the Building a productivity app for Apple Watch sample code from Apple and other examples on navigation with the new NavigationStack in WatchOS 9, iOS 16 etc... import SwiftUI @main struct Test_Watch_App_Watch_AppApp: App {     @SceneBuilder var body: some Scene {         WindowGroup {             TabView {                 NavigationStack {                     ScrollView {                         VStack {                             NavigationLink("Mint", value: Color.mint)                             NavigationLink("Pink", value: Color.pink)                             NavigationLink("Teal", value: Color.teal)                         }                     }                     .navigationDestination(for: Color.self) { color in                         Text("Hello").background(color)                     }                     .navigationTitle("Colors")                 }                 NavigationStack {                     ScrollView {                         VStack {                             NavigationLink("headline", value: Font.headline)                             NavigationLink("title", value: Font.title)                             NavigationLink("caption", value: Font.caption)                         }                     }                     .navigationDestination(for: Font.self) { font in                         Text("Hello").font(font)                     }                     .navigationTitle("Fonts")                 }             }.tabViewStyle(.page)         }     } } The problem here is, when selecting any of the Navigation Links, the child view still displays the Tab Bar page indicators and allows you to swipe between the tabs, I don't want this. The functionality as I'd like exists int eh Apple Fitness app on the Watch. The app launches in the Activity Tab. You can swipe across to Sharing, select a person, and in that view it's not then possible to swipe straight back to Activity. I've tried Embedding the whole TabView in a NavigationStack and removing the NavigationStacks per tab. This works as far as fixing the child views hiding the TabBar page indicator controls and swiping. However, it then breaks NavigationTitles on launch and when moving in and out of Childs, so I don't think it should be this way. Any help very appreciated.
1
0
3.5k
Feb ’23
SwiftUI NavigationSplitView Bug?
Hi All! I am working on a Multiplatform SwiftUI app and I've encountered an issue with NavigationSplitView. My app's ContentView is a NavigationSplitView sidebar and detail. The sidebar is a list with several NavigationLinks. (I haven't adopted programmatic navigation because of the simplicity this sidebar.) One of the NavigationLinks brings the user to a Table with several rows and columns. Then, when I go to select an item on the table, a row shows selected for a split second, before deselecting itself again. Then, I can use the table as normal. This happens every time the view is opened. The reason I think that this is an issue with NavigationSplitView is because when I use the legacy NavigationView, everything is fine. Is this normal behavior for NavigationSplitView, and if it is, how to I make it so that my table receives focus when the NavigationLink is open?
1
0
1.2k
Jan ’23
NavigationSplitView does not run .task for each detail view instance
NavigationSplitView does not run .task for each detail view instance. I'm trying to update my code from NavigationView to NavigationSplitView. I was having trouble, since I rely upon .task to update the @State of my detail view. It does not update this state in the detail view when using NavigationSplitView. Please see my comments in the code snippet below. Does anyone have any suggestions? FWIW I have also filed FB11932889. Thanks for any help. import SwiftUI enum Category: CaseIterable, Hashable {   case first   case second } struct CategoryRow: View {   let category: Category   var body: some View {     Text("Row: \(String(describing: category))")   } } struct CategoryDetail: View {   enum LoadingState {     case none     case loading     case loaded     case error   }   let category: Category   @State private var loadingState: LoadingState = .none   var body: some View {     VStack {       Text("Category: \(String(describing: category))")       Text("LoadingState: \(String(describing: loadingState))")     }     .task {       // If this .task does not run ever, the view will show a .none Category.       // If this .task runs, the view will start by showing .loading, and then .loaded       // The bug found when this is in CategoryNavigationSplitView that: this .task does not run for the .second category,       //  but the @State is not reset, it will show .loaded for the second category chosen!       //  I expect this .task to run each time, and not carry over the @State from       //  previous CategoryDetail. It must be a new CategoryDetail View, since the       //  let Category constant is changing.       // When this is in CategoryNavigationView, the .task runs as expected.       loadingState = .loading       do {         try await Task.sleep(for: .seconds(2))         loadingState = .loaded       } catch {         loadingState = .error       }     }   } } struct CategoryNavigationSplitView: View {   @State var selectedCategory: Category?   var body: some View {     NavigationSplitView {       List(Category.allCases, id: \.self, selection: $selectedCategory) { category in         NavigationLink(value: category) { CategoryRow(category: category) }       }     } detail: {       if let selectedCategory {         CategoryDetail(category: selectedCategory)       } else {         Text("Select a Category")       }     }   } } struct CategoryNavigationView: View {   @State var selectedCategory: Category?   var body: some View {     NavigationView {       List(Category.allCases, id: \.self, selection: $selectedCategory) { category in         NavigationLink {           CategoryDetail(category: category)         } label: {           CategoryRow(category: category)         }       }     }     Text("Select a Category")   } }
4
1
1.9k
Jan ’23
NavigationSplitView
I need help with this topic please. I'm interested in the three column layout version. Column one I want my list of Core Data Entities, Column two I want a list of my Core Data Entity's ListView items, and for Column three I want the detail view of the selected list view item. Any help on figuring out the best way to accomplish this would be much appreciated. Thanks
2
0
1.1k
Jan ’23
Reset NavigationStack when changing selection of NavigationSplitView
I'm trying to build an app that has a NavigationSplitView and a NavigationStack in the detail View. The normal flow works fine, but if I navigate to the second page on the detail view and then select another menu item (i.e. the second item), I'm still on the detail page of the first menu item. The underlying view of the second detail view changes. This can be observed by the change of the back button label. How do I ensure that my NavigationStack is also reset when I change the selection? import SwiftUI enum Option: String, Equatable, Identifiable {     case first     case second     var id: Option { self } } struct ContentView: View {     @State private var selection: Option?     var body: some View {         NavigationSplitView {             List(selection: $selection) {                 NavigationLink(value: Option.first) {                     Text("First")                 }                 NavigationLink(value: Option.second) {                     Text("Second")                 }             }         } detail: {             switch selection {             case .none:                 Text("Please select one option")             case .some(let wrapped):                 NavigationStack {                     DetailView(title: wrapped.rawValue)                 }             }         }         .navigationSplitViewStyle(.balanced)     } } struct DetailView: View {     private var title: String     init(title: String) {         self.title = title     }     var body: some View {         List {             NavigationLink {                 Text(title)             } label: {                 Text("Show \(title) detail")             }         }         .navigationTitle(title)     } }
2
1
3.4k
Jan ’23
iOS 16 crash on dismiss sheet with navigationView
Hi, I've recently experienced a weird crash that only happening on iOS 16 device. When dismiss a sheet which contains NavigationView it sometime crashes. It is not 100% reproducible but relatively easy to get crash. The same build running on iOS 15 device is totally fine. The crash report shows nothing useful and the stack trace shows none of my code so I'm not sure what's going on in here. Any help is much appreciated. 2022-09-28_14-52-44.0187_+1300-aa6ef929623289970774d4bf7cc3f8835df8fbce.crash
20
11
10k
Jan ’23
Migrating selection-based navigation inside ForEach
Below is my deprecated solution to immediately go the the destination view when creating a new item with the "plus"-Button. I don't get how to migrate the deprecated 'init(destination:tag:selection:label:)' to the new NavigationStack or NavigationSplitView Any help appreciated. struct ItemList: View { @StateObject private var itemStore = ItemStore() @State private var indexItem: Int? var body: some View { NavigationView { List { let itemStoreZip = zip(itemStore.allItems.indices, itemStore.allItems) ForEach(Array(itemStoreZip), id: \.0) {i, item in let itemBind = $itemStore.allItems[i] NavigationLink(destination: ItemDetail(item: itemBind), tag: i, selection: $indexItem) { ItemRow(item: item) } } .onDelete { indexSet in itemStore.removeItem(indexSet: indexSet) } .onMove { indices, newOffset in itemStore.moveItem(source: indices, to: newOffset) } } .navigationTitle("Homepwner") .toolbar { ToolbarItem(placement: ToolbarItemPlacement.navigationBarTrailing) { EditButton() } ToolbarItem(placement: ToolbarItemPlacement.navigationBarLeading) { Button { (indexItem,_) = itemStore.newItem() } label: { Image(systemName: "plus") } } } } } }
2
0
982
Jan ’23
Driving NavigationSplitView with something other than List?
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.
Replies
14
Boosts
5
Views
7.3k
Activity
Feb ’26
NavigationSplitView hide sidebar toggle button
I'm trying to implement the same UI used by the Settings app on iPad: a split view with two columns that are visible at all times. This code produces the layout i want, but I would like to hide the "toggle sidebar visibility" button that the system introduces. Is there a SwiftUI API I can use to hide this button? Maybe an alternate way to setup views that tells the system that the button is not necessary? struct SomeView: View { var body: some View { NavigationSplitView( columnVisibility: .constant(.all), sidebar: { Text("sidebar") }, detail: { Text("detail") } ) .navigationSplitViewStyle(.balanced) } }
Replies
7
Boosts
3
Views
8.6k
Activity
Mar ’25
SwiftUI NavigationLink freezing when tapped
Any one getting any issues with NavigaitonLink to seemingly innocuous views freezing when tapped on? 1 CPU at 100% memory steadily increasing until app gets killed by the system. Will freeze if any NavigationLink on the view is tapped if certain views are linked to using NavigaitonLink. I note some people have been getting similar freezes if they use @AppStorage, but I'm not using @AppStorage. I do use CoreData tho. tho I have some views that use core data that don't freeze. https://developer.apple.com/forums/thread/708592?page=1#736374022 has anyone experienced similar issues? or know the cause. it doesn't seem to be any of my code because if I pause the debugger it stops on system code.
Replies
18
Boosts
2
Views
11k
Activity
Nov ’24
Toolbar Menu button seems to look disabled
Overview On macOS, in a NavigationSplitView when the menu button is added to the detail view toolbar, it seems to look disabled Environment Xcode: 14.1 beta 3 (14B5033e) macOS: 13.0 Beta (22A5365d) Code: struct ContentView: View { @State private var selectedNumber: Int? var body: some View { NavigationSplitView { List(0..<100, selection: $selectedNumber) { number in Text("cell \(number)") } } detail: { Text("Detail") .toolbar { ToolbarItem { Menu { Button("aa") {} Button("bb") {} } label: { Label("Add Bookmark", systemImage: "book") } } } } } } Steps to reproduce: Run the project on macOS Select cell 0 on the sidebar Click on the book toolbar button and notice the menu appear Select cell 1 on the sidebar Expected Behaviour After step 4, the book toolbar button should look prominent (like it is enabled) Actual Behaviour After step 4, the book toolbar button looks like it is disabled. Screenshot
Replies
1
Boosts
1
Views
1.7k
Activity
Nov ’23
Embedding a NavigationStack within the detail view of a NavigationSplitView
I'm using a two column NavigationSplitView, where the view passed for the detail column is the root of a NavigationStack. The navigation works as expected, but the navigationTitle and toolbar elements of the detail view are very slightly delayed when the view appears on iOS, such that they 'pop' in rather than smoothly animating like normal. Returning to the root of the view from views higher in this stack animates as expected. Has anyone seen anything like this before? Thanks!
Replies
6
Boosts
0
Views
2.4k
Activity
Oct ’23
NavigationSplitView two and three column interfaces in the same app
I am currently learning to create multiplatform applications using SwiftUI and NavigationSplitView, and I faced the problem of arranging different Views in the same App. Let's open the default Notes application, and here, we can see a switch between two and three-column views of the content. So my question is, how to arrange this kind of view for different App pages using NavigationSplitView? First page has two columns interface Second has three columns
Replies
3
Boosts
0
Views
4k
Activity
Aug ’23
NavigationStack not working correctly in sheet
I am currently trying to build a NavigationManager with programmatic navigation. For that I'm using the NavigationPath combined with NavigationDestination. Sadly facing the following issue: navigationDestionation is not being recognised when located in sheet. Im receiving the following message when trying to update the path of the NavigationStack within the sheet. A NavigationLink is presenting a value of type “PathType” but there is no matching navigationDestination declaration visible from the location of the link. The link cannot be activated. Note: Links search for destinations in any surrounding NavigationStack, then within the same column of a NavigationSplitView. Here is some simplified code snipped of the implementation. struct RootView: View { @State private var isPresented: Bool = true var body: some View { Button("Open Modal", action: { self.isPresented.toggle() }) .sheet(isPresented: self.$isPresented, content: { ModalContent() }) } } private struct ModalContent: View { @State private var path = NavigationPath([PathType.configuration]) var body: some View { NavigationStack(path: self.$path) { VStack { Text("Placeholder") } .navigationDestination(for: PathType.self) { pathType in switch pathType { case .configuration: Text("Configuration") default: Color.red } } } } }
Replies
1
Boosts
1
Views
2.2k
Activity
May ’23
Selection state is lost when navigating to/from home screen
Hi! When using the Sample "NavigationCookbook" in the two column layout, the selection in the first column is not remembered, when navigating to the Home Screen and back. This behaviour can be reproduced by starting the app on the iPad or simulator, selecting for example "Pancake" and then navigating to the home screen and back into the navigation. Sometimes this (the navigation to/back from the home screen) has to be done twice, to lose the selection. In the console log you can see the message "Update NavigationAuthority bound path tried to update multiple times per frame." appearing. Not sure if this has something todo with the selection being lost. This is on iOS 16.4.1 not sure if the behaviour before was different. Anybody experiences the same behaviour? Bug in SwiftUI or in the sample app? Cheers, Michael
Replies
2
Boosts
1
Views
1.1k
Activity
Apr ’23
How to add interactive pop gesture using SwiftUI in iOS16?
Considering the latest updates added in iOS16 in terms of programmatic navigation, is there a dedicated SwiftUI way of adding the interactive-pop-gesture interaction in the NavigationStack / NavigationSplitView?
Replies
0
Boosts
0
Views
892
Activity
Mar ’23
Getting Large Titles on WatchOS with a Navigation Stack
On my Watch app pre-WatchOS 9 I had code as follows: ` TabView { NavigationView { TodayView(model: delegate.model) .navigationBarTitleDisplayMode(.large) } NavigationView { SettingsView(model: delegate.model) } } .tabViewStyle(.page) However, for WatchOS 9 I'm using the new NavigationStack like this: ` NavigationStack { TabView { TodayView(model: delegate.model) .navigationBarTitleDisplayMode(.large) The issue is, with WatchOS 9 the title always displays as .inline and never large. I've tried embedding a list or scroll view. I've also tried placing a navigationView within the NavigationStack and TabView, that just makes duplicate titles. So, using the NavigationStack with a TabView on WatchOS 9, how do you get large titles? Thanks
Replies
3
Boosts
0
Views
1.8k
Activity
Mar ’23
Why is my navigationPath not reaching views further along my stack?
I've implemented a navigation stack that appends the next view's view model so that the appending and .navigationDestination looks like the below. Whenever I press the continue button to add the viewModel to the path in the ContentView (the child of BumperScreen and the second in the path), the app just stops. I tried isolating the problem with a test project using the same methodology for navigation and have been able to navigate several views, almost infinitely. I cannot replicate this issue and am having a hard time understanding why one is working, and not the other. struct BumperScreen: View { @State private var path = NavigationPath() @StateObject var viewModel: BumperScreenViewModel @StateObject var sheetManager = SheetManager() init(viewModel: @autoclosure @escaping () -> BumperScreenViewModel) { self._viewModel = .init(wrappedValue: viewModel()) } var body: some View { if isDoneOnboarding { HomeView() .environmentObject(sheetManager) } else { NavigationStack(path: $path) { ZStack { Color(.Gold) .ignoresSafeArea() VStack { if show { Spacer() loadAnimation .frame(width: 150, height: 150) .task { try? await viewModel.getDataFromAPI() try? await Task.sleep(for: Duration.seconds(1)) path.append(ContentViewViewModel()) doneLoading.toggle() show.toggle() } Spacer() } else if doneLoading { EmptyView() } else { launchAnimation } } .navigationDestination(for: ContentViewViewModel.self) { model in ContentView(viewModel: model, path: $path) .environmentObject(sheetManager) } } } } } } Which leads the user to the second view struct ContentView: View { @EnvironmentObject var sheetManager: SheetManager @StateObject var viewModel: ContentViewViewModel @Binding var path: NavigationPath var body: some View { ZStack { Color(.trulliGold) .ignoresSafeArea() VStack { Spacer() headerStatement Spacer() VStack { privacyPolicy bluetoothPolicy locationsPolicy notificationsPolicy apprunningPolicy } Spacer() Spacer() continueButton } } .popup(with: sheetManager) .navigationBarBackButtonHidden() } var continueButton: some View { Button(action: { print("pressed") path.append(WelcomeScreenViewViewModel()) }) { Text("CONTINUE") } .navigationDestination(for: WelcomeScreenViewViewModel.self) { model in WelcomeScreenView(viewModel: model, path: $path) } } } Which goes to struct WelcomeScreenView: View { @StateObject var viewModel: WelcomeScreenViewViewModel @Binding var path: NavigationPath var body: some View { ZStack { Color(.trulliGold) .ignoresSafeArea() VStack(alignment: .center, spacing: 8) { header Spacer() tabView Spacer() Spacer() nextButton closeButton } } .navigationDestination(for: SetupGuideSpeakerSearchViewViewModel.self) { model in SetupGuideSpeakerSearchView(viewModel: model, path: $path ) } .navigationBarBackButtonHidden() } } I've tried isolating the issue to a debug project and have been able to navigate several views therein with no issue. debug project
Replies
0
Boosts
0
Views
1.4k
Activity
Mar ’23
What is the best way for other ViewModel to get a reference to NavigationModel according to WWDC example?
In https://developer.apple.com/wwdc22/10054 it is shown that the best way to organize an iPad layout is by: struct TwoColumnContentView: View { @Binding var showExperiencePicker: Bool @EnvironmentObject private var navigationModel: NavigationModel var categories = Category.allCases var dataModel = DataModel.shared var body: some View { 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) } } } } NavigationModel defined as final class NavigationModel: ObservableObject, Codable { @Published var selectedCategory: Category? @Published var recipePath: [Recipe] @Published var columnVisibility: NavigationSplitViewVisibility } But what happens when in a child view, it triggers off some action in some other ViewModel that needs to update the navigation stack? struct ChildViewModel { func childViewCalledAndDidSomething { //now I need to update recipePath, how? } }
Replies
0
Boosts
0
Views
826
Activity
Mar ’23
Right Approach to test SwiftUI Views
How do we test SwiftUI views? Can we test them in Unit testing? If so we don't have proper apis to get the view hierarchy or the required set of objects for testing. We have to rely on using identifier for every object and extract the view with the id? I have seen many using ViewInspector which extracts the view hierarchy and has apis to test the array of views matching a text etc. But is it using a right approach for extracting views will it have issues when ever the Xcode or Os is upgraded? Is snapshot testing right approach for swiftUI views?
Replies
1
Boosts
0
Views
3.1k
Activity
Mar ’23
Hide & Disable TabBar when in NavigationDestination Subview - Apple Watch
I'm trying to create a UI layout and navigation functionality similar to the Apple Fitness app on Apple Watch. This is all WatchOS 9 so no need for older API support, phew! I want to have NavigationTitle set for each view in a TabBar. I want each selected NavigationDestination to hide the TabBar controls and disable swiping when opened. I want the NavigationTitle and update to remain whilst navigating between Tabs and Childs. I've created this sample code based off the Building a productivity app for Apple Watch sample code from Apple and other examples on navigation with the new NavigationStack in WatchOS 9, iOS 16 etc... import SwiftUI @main struct Test_Watch_App_Watch_AppApp: App {     @SceneBuilder var body: some Scene {         WindowGroup {             TabView {                 NavigationStack {                     ScrollView {                         VStack {                             NavigationLink("Mint", value: Color.mint)                             NavigationLink("Pink", value: Color.pink)                             NavigationLink("Teal", value: Color.teal)                         }                     }                     .navigationDestination(for: Color.self) { color in                         Text("Hello").background(color)                     }                     .navigationTitle("Colors")                 }                 NavigationStack {                     ScrollView {                         VStack {                             NavigationLink("headline", value: Font.headline)                             NavigationLink("title", value: Font.title)                             NavigationLink("caption", value: Font.caption)                         }                     }                     .navigationDestination(for: Font.self) { font in                         Text("Hello").font(font)                     }                     .navigationTitle("Fonts")                 }             }.tabViewStyle(.page)         }     } } The problem here is, when selecting any of the Navigation Links, the child view still displays the Tab Bar page indicators and allows you to swipe between the tabs, I don't want this. The functionality as I'd like exists int eh Apple Fitness app on the Watch. The app launches in the Activity Tab. You can swipe across to Sharing, select a person, and in that view it's not then possible to swipe straight back to Activity. I've tried Embedding the whole TabView in a NavigationStack and removing the NavigationStacks per tab. This works as far as fixing the child views hiding the TabBar page indicator controls and swiping. However, it then breaks NavigationTitles on launch and when moving in and out of Childs, so I don't think it should be this way. Any help very appreciated.
Replies
1
Boosts
0
Views
3.5k
Activity
Feb ’23
SwiftUI NavigationSplitView Bug?
Hi All! I am working on a Multiplatform SwiftUI app and I've encountered an issue with NavigationSplitView. My app's ContentView is a NavigationSplitView sidebar and detail. The sidebar is a list with several NavigationLinks. (I haven't adopted programmatic navigation because of the simplicity this sidebar.) One of the NavigationLinks brings the user to a Table with several rows and columns. Then, when I go to select an item on the table, a row shows selected for a split second, before deselecting itself again. Then, I can use the table as normal. This happens every time the view is opened. The reason I think that this is an issue with NavigationSplitView is because when I use the legacy NavigationView, everything is fine. Is this normal behavior for NavigationSplitView, and if it is, how to I make it so that my table receives focus when the NavigationLink is open?
Replies
1
Boosts
0
Views
1.2k
Activity
Jan ’23
NavigationSplitView does not run .task for each detail view instance
NavigationSplitView does not run .task for each detail view instance. I'm trying to update my code from NavigationView to NavigationSplitView. I was having trouble, since I rely upon .task to update the @State of my detail view. It does not update this state in the detail view when using NavigationSplitView. Please see my comments in the code snippet below. Does anyone have any suggestions? FWIW I have also filed FB11932889. Thanks for any help. import SwiftUI enum Category: CaseIterable, Hashable {   case first   case second } struct CategoryRow: View {   let category: Category   var body: some View {     Text("Row: \(String(describing: category))")   } } struct CategoryDetail: View {   enum LoadingState {     case none     case loading     case loaded     case error   }   let category: Category   @State private var loadingState: LoadingState = .none   var body: some View {     VStack {       Text("Category: \(String(describing: category))")       Text("LoadingState: \(String(describing: loadingState))")     }     .task {       // If this .task does not run ever, the view will show a .none Category.       // If this .task runs, the view will start by showing .loading, and then .loaded       // The bug found when this is in CategoryNavigationSplitView that: this .task does not run for the .second category,       //  but the @State is not reset, it will show .loaded for the second category chosen!       //  I expect this .task to run each time, and not carry over the @State from       //  previous CategoryDetail. It must be a new CategoryDetail View, since the       //  let Category constant is changing.       // When this is in CategoryNavigationView, the .task runs as expected.       loadingState = .loading       do {         try await Task.sleep(for: .seconds(2))         loadingState = .loaded       } catch {         loadingState = .error       }     }   } } struct CategoryNavigationSplitView: View {   @State var selectedCategory: Category?   var body: some View {     NavigationSplitView {       List(Category.allCases, id: \.self, selection: $selectedCategory) { category in         NavigationLink(value: category) { CategoryRow(category: category) }       }     } detail: {       if let selectedCategory {         CategoryDetail(category: selectedCategory)       } else {         Text("Select a Category")       }     }   } } struct CategoryNavigationView: View {   @State var selectedCategory: Category?   var body: some View {     NavigationView {       List(Category.allCases, id: \.self, selection: $selectedCategory) { category in         NavigationLink {           CategoryDetail(category: category)         } label: {           CategoryRow(category: category)         }       }     }     Text("Select a Category")   } }
Replies
4
Boosts
1
Views
1.9k
Activity
Jan ’23
NavigationSplitView
I need help with this topic please. I'm interested in the three column layout version. Column one I want my list of Core Data Entities, Column two I want a list of my Core Data Entity's ListView items, and for Column three I want the detail view of the selected list view item. Any help on figuring out the best way to accomplish this would be much appreciated. Thanks
Replies
2
Boosts
0
Views
1.1k
Activity
Jan ’23
Reset NavigationStack when changing selection of NavigationSplitView
I'm trying to build an app that has a NavigationSplitView and a NavigationStack in the detail View. The normal flow works fine, but if I navigate to the second page on the detail view and then select another menu item (i.e. the second item), I'm still on the detail page of the first menu item. The underlying view of the second detail view changes. This can be observed by the change of the back button label. How do I ensure that my NavigationStack is also reset when I change the selection? import SwiftUI enum Option: String, Equatable, Identifiable {     case first     case second     var id: Option { self } } struct ContentView: View {     @State private var selection: Option?     var body: some View {         NavigationSplitView {             List(selection: $selection) {                 NavigationLink(value: Option.first) {                     Text("First")                 }                 NavigationLink(value: Option.second) {                     Text("Second")                 }             }         } detail: {             switch selection {             case .none:                 Text("Please select one option")             case .some(let wrapped):                 NavigationStack {                     DetailView(title: wrapped.rawValue)                 }             }         }         .navigationSplitViewStyle(.balanced)     } } struct DetailView: View {     private var title: String     init(title: String) {         self.title = title     }     var body: some View {         List {             NavigationLink {                 Text(title)             } label: {                 Text("Show \(title) detail")             }         }         .navigationTitle(title)     } }
Replies
2
Boosts
1
Views
3.4k
Activity
Jan ’23
iOS 16 crash on dismiss sheet with navigationView
Hi, I've recently experienced a weird crash that only happening on iOS 16 device. When dismiss a sheet which contains NavigationView it sometime crashes. It is not 100% reproducible but relatively easy to get crash. The same build running on iOS 15 device is totally fine. The crash report shows nothing useful and the stack trace shows none of my code so I'm not sure what's going on in here. Any help is much appreciated. 2022-09-28_14-52-44.0187_+1300-aa6ef929623289970774d4bf7cc3f8835df8fbce.crash
Replies
20
Boosts
11
Views
10k
Activity
Jan ’23
Migrating selection-based navigation inside ForEach
Below is my deprecated solution to immediately go the the destination view when creating a new item with the "plus"-Button. I don't get how to migrate the deprecated 'init(destination:tag:selection:label:)' to the new NavigationStack or NavigationSplitView Any help appreciated. struct ItemList: View { @StateObject private var itemStore = ItemStore() @State private var indexItem: Int? var body: some View { NavigationView { List { let itemStoreZip = zip(itemStore.allItems.indices, itemStore.allItems) ForEach(Array(itemStoreZip), id: \.0) {i, item in let itemBind = $itemStore.allItems[i] NavigationLink(destination: ItemDetail(item: itemBind), tag: i, selection: $indexItem) { ItemRow(item: item) } } .onDelete { indexSet in itemStore.removeItem(indexSet: indexSet) } .onMove { indices, newOffset in itemStore.moveItem(source: indices, to: newOffset) } } .navigationTitle("Homepwner") .toolbar { ToolbarItem(placement: ToolbarItemPlacement.navigationBarTrailing) { EditButton() } ToolbarItem(placement: ToolbarItemPlacement.navigationBarLeading) { Button { (indexItem,_) = itemStore.newItem() } label: { Image(systemName: "plus") } } } } } }
Replies
2
Boosts
0
Views
982
Activity
Jan ’23