SwiftUI Tutorial: Navigation | raywenderlich.com

In this tutorial, you’ll use SwiftUI to implement the navigation of a master-detail app. You’ll learn how to implement a navigation stack, a navigation bar button, a context menu and a modal sheet.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/5824937-swiftui-tutorial-navigation

Thanks for a great tutorial. With regards to the SplitView section, is there a way to have the master view always show while on iPad and not have to swipe right to show it? It would be similar to the Settings app on the iPad where the master view always shows on the left and then the detail is on the right. Thanks.

hi Aoi! do you mean in portrait orientation? there’s a partial solution on Stack Overflow — you add padding to the NavigationView, which squeezes both master and detail view onto the screen. Use .padding(1) to minimise the screen loss.

Thanks. Yes, a partial work around. What I was looking for was the functionality that UISplitView has: preferredDisplayMode.allVisible. The workaround makes portrait mode look like .allVisible but seems to break in landscape mode for me. I guess this is something that Apple hasn’t provided for yet.? Is there a way to add a back button on the detail view so that the user when presented with just the detail view can see that the masterview is off screen and make it appear without swiping?
Mike

hi Mike! yes, Apple hasn’t yet implemented everything from UIKit, so they provide UIViewControllerRepresentable and UIViewRepresentable — you can extend UISplitViewController to conform to UIViewControllerRepresentable, then use it in your SwiftUI app.

The other standard suggestion is to force StackNavigationViewStyle, so your iPad app behaves like the iPhone version — back button etc.

Thanks for clarifying how SwiftUI applies indices. I’ve followed this and a couple other tutorials, but struggling to apply to a list within a list without creating additional classes, structs, or enums.

In this example, rather than use tabs, how would one “group” based on disciplines? In other words, the master would list the disciplines, each with a navigation link to a list of artwork of that type of discipline and then each of those would have a link to the DetailView.

hi Daniel! you’d just make the first detail view a list with navigation link. Here’s a rough draft. An enum would be useful, and a func or computed property to filter the full array of artworks. Here, I just pass the statues array.

Live preview shows two back buttons on the final artwork view, so you can return to Statues or to Disciplines … looks odd, but useful, I guess :wink:

    import SwiftUI

    struct ContentView: View {
      let disciplines = ["Statue", "Mural", "Plaque"]
      
      let statues = ["Kuhio", "Kalakaua"]
      let murals = ["Water", "Couple"]
      let plaques = ["Earhart", "Marin"]
      
      var body: some View {
        NavigationView {
          List(disciplines, id: \.self) { discipline in
            NavigationLink(
            destination: DetailView(discipline: discipline, artworks: self.statues)) {
              Text(discipline)
            }
          }
          .navigationBarTitle("Disciplines")
        }
      }
    }

    struct DetailView: View {
      let discipline: String
      let artworks: [String]
      
      var body: some View {
        NavigationView {
          List(artworks, id: \.self) { artwork in
            NavigationLink(
            destination: ArtView(artwork: artwork)) {
              Text(artwork)
            }
          }
          .navigationBarTitle("Statues")
        }
      }
    }

    struct ArtView: View {
      let artwork: String
      var body: some View {
        Text(artwork)
      }
    }

    struct ContentView_Previews: PreviewProvider {
      static var previews: some View {
        ContentView()
      }
    }

Thanks Audrey!
I just started the Functions course, so hopefully I can figure out a way to manipulate the full array of artworks to get the data in the right formats.

Hi!
I’ve download the finished project and ran it in the latest Xcode: Version 11.3 (11C29)
When tapping an item, getting into the detail screen, then going back to the main screen, and then clicking the same item again the item appears to be in selected state, and I’m not being directed to the detail screen:
image

Haven’t found a solution online, anyone have any idea why is it happening?

Hi Oron! This is a simulator bug. I wrote a reply here

Hi, this is a great tut. Can I have a question about Eager Evaluation?
I added a breakpoint in DetailView, at body param then I run the app. I thought once it initialise DetailView, it should stop at the breakpoint. Could you please give more example or detail? Thanks

hi Doraemon! I don’t think breakpoints in SwiftUI views work the same as in a view controller. There isn’t any “execution order” as such. That’s why I put the print statement in the Artwork init, so you can see all of them are “downloaded” even when their list item isn’t on screen.

The next version of SwiftUI announced at WWDC 2020 will allow lazy loading for grids and stacks. And lists will be lazy loading.

1 Like

This tutorial is more than six months old so questions are no longer supported at the moment for it. Thank you!