NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

Showing book details

Paul Hudson    @twostraws   

When the user taps a book in ContentView we’re going to present a detail view with some more information – the genre of the book, their brief review, and more. We’re also going to reuse our new RatingView, and even customize it so you can see just how flexible SwiftUI is.

To make this screen more interesting, we’re going to add some artwork that represents each category in our app. I’ve picked out some artwork already from Unsplash, and placed it into the project11-files folder for this book – if you haven’t downloaded them, please do so now and then drag them into your asset catalog.

Unsplash has a license that allows us to use pictures commercially or non-commercially, with or without attribution, although attribution is appreciated. The pictures I’ve added are by Ryan Wallace, Eugene Triguba, Jamie Street, Alvaro Serrano, Joao Silas, David Dilbert, and Casey Horner – you can get the originals from if you want.

Next, create a new SwiftUI view called “DetailView”. This only needs one property, which is the book it should show, so please add that now:

let book: Book

Even just having that property is enough to break the preview code at the bottom of DetailView.swift. Previously this was easy to fix because we just sent in an example object, but with Core Data involved things are messier: creating a new book also means having a managed object context to create it inside.

To fix this, we can update our preview code to create a temporary managed object context, then use that to create our book. Once that’s done we can pass in some example data to make our preview look good, then use the test book to create a detail view preview.

Creating a managed object context means we need to start by importing Core Data. Add this line near the top of DetailView.swift, next to the existing import:

import CoreData

As for the previews code itself, replace whatever you have now with this:

struct DetailView_Previews: PreviewProvider {
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

    static var previews: some View {
        let book = Book(context: moc)
        book.title = "Test book" = "Test author"
        book.genre = "Fantasy"
        book.rating = 4 = "This was a great book; I really enjoyed it."

        return NavigationView {
            DetailView(book: book)

As you can see, creating a managed object context involves telling the system what concurrency type we want to use. This is another way of saying “which thread do you plan to access your data using?” For our example, using the main queue – that’s the one the app was launched using – is perfectly fine.

With that done we can turn our attention to more interesting problems, namely designing the view itself. To start with, we’re going to place the category image and genre inside a ZStack, so we can put one on top of the other nicely. I’ve picked out some styling that I think looks good, but you’re welcome to experiment with the styling all you want – the only thing I’d recommend you definitely keep is the ScrollView, which ensures our review will fit fully onto the screen no matter how long it is, what device the user has, or whether they have adjusted their font sizes or not.

Replace the current body property with this:

ScrollView {
    ZStack(alignment: .bottomTrailing) {
        Image(book.genre ?? "Fantasy")

        Text(book.genre?.uppercased() ?? "FANTASY")
            .offset(x: -5, y: -5)
.navigationTitle(book.title ?? "Unknown Book")

That places the genre name in the bottom-right corner of the ZStack, with a background color, bold font, and a little padding to help it stand out.

Below that ZStack we’re going to add the author, review, and rating. We don’t want users to be able to adjust the rating here, so instead we can use another constant binding to turn this into a simple read-only view. Even better, because we used SF Symbols to create the rating image, we can scale them up seamlessly with a simple font() modifier, to make better use of all the space we have.

So, add these views directly below the previous ZStack:

Text( ?? "Unknown author")

Text( ?? "No review")

RatingView(rating: .constant(Int(book.rating)))

That completes DetailView, so we can head back to ContentView.swift to change the navigation link so it points to the correct thing:

NavigationLink {
    DetailView(book: book)
} label: {

Now run the app again, because you should be able to tap any of the books you’ve entered to show them in our new detail view.

Hacking with Swift is sponsored by Waldo

SPONSORED Thorough mobile testing hasn’t been efficient testing. With Waldo Sessions, it can be! Test early, test often, test directly in your browser and share the replay with your team.

Try for free today!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.6/5

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.