Your Second iOS & SwiftUI App

Nov 4 2021 · Swift 5.5, iOS 15, Xcode 13

Part 1: List View Fundamentals

07. Navigation

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 06. Lists Next episode: 08. Challenge: View Reuse
Transcript: 07. Navigation

We’ve got a bare-bones list up and running, and we’re ready to start adding features to our app. We can start by creating a detail view to show us more about each book when we tap on a row.

By the end of the course, it will look something like this:

But, for this episode, let’s just get some basics hooked up and aim for this:

We’ll call this the DetailView, and create a new SwiftUI file for it, at the bottom of the Views group.

Whenever I start a new file, I select all with command-A and then re-indent with Control-I. That’s just because Xcode’s defaults don’t conform to my settings when I create new files.

import SwiftUI

struct DetailView: View {
  var body: some View {
    Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
  }
}

struct DetailView_Previews: PreviewProvider {
  static var previews: some View {
    DetailView()
  }
}

OK, so we’ve got a detail view, and it’s going to display our book data… So it’s going to require a book property.

struct DetailView: View {
  let book: Book

  var body: some View {

Pass the default one to the preview.

DetailView(book: .init())

Now that we’ll be able to see what we’re doing. Add an image for the book in the body.

  var body: some View {
    Book.Image(title: book.title)
  }

Then stack that vertically with a Spacer underneath, to bring it to the top.

    VStack {
      Book.Image(title: book.title)
      Spacer()
    }

That’s our bare-bones detail view. To navigate TO this view, we need to do some more work back in ContentView.swift.

Try hitting shift-command-o, and then look for “BookRow”, so you can easily jump straight to the BookRow type.

When you tap on each one of these rows, that should bring up an instance of your new Detail View, provided with the book you tapped on. To do that, create a NavigationLink at the top of “body”.

  var body: some View {
    NavigationLink(
      destination: /*@START_MENU_TOKEN@*/Text("Destination")/*@END_MENU_TOKEN@*/,
      label: {
        /*@START_MENU_TOKEN@*/Text("Navigate")/*@END_MENU_TOKEN@*/
      })
    HStack {

The destination you need is the instance of Detail View I just mentioned…

destination: DetailView(book: <#T##Book#>),

…with the BookRow’s book passed along to it.

book: book)

The label for the link is going to be the entirety of the body we already had. So make sure this whole HStack is wrapped in the Navigation Link’s trailing closure.

  var body: some View {
    NavigationLink(
      destination: DetailView(book: book)
    ) {
      HStack {
        Book.Image(title: book.title)

        VStack(alignment: .leading) {
          Text(book.title)
            .font(.title2)
          Text(book.author)
            .font(.title3)
            .foregroundColor(.secondary)
        }
        .lineLimit(1)
      }
    }
  }

Look on the right of the preview, and you should see these right-pointing chevrons, indicating that tapping will lead you to another view.

But, the rows are all greyed out. Which means there’s no way to interact with them. And that is because a Navigation Link requires a parent Navigation View to do anything.

We’ll add that directly to the List in content view. There’s not an easy option to “embed in Navigaiton View”, so I’ll embed in a Group again, and then change it to the Navigation View I want.

struct ContentView: View {
  var body: some View {
    NavigationView {
      List(Library().sortedBooks, id: \.title) { book in
        BookRow(book: book)
      }
    }
  }
}

And now they’re tappable! We’ll try that out it a moment! First, title the navigation view “My Library”.

        BookRow(book: book)
      }
      .navigationTitle("My Library")
    }

Notice how that’s a modifier on the List, not the navigation view itself. If you move it down a line with shift-command-right bracket

…the title won’t take effect.

It works this way so that you’re able to set the title dynamically, from any child view you want.

Now we can try it out, s hit the Live Preview button. As you scroll down, the title moves out of the way, and you’re able to navigate to detail views, which automatically get that title as a “back” button!