[SwiftUI 100天] Bookworm-part7 显示图书细节

261 阅读4分钟
译自 www.hackingwithswift.com/books/ios-s…
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀

显示图书细节

当用户点击ContentView里的一本图书时,我们要呈现一个细节视图,展示更多的信息 —— 书的流派,简单的评价,等等。我们会重用RatingView,通过自定义,你会发现 SwiftUI 有多么灵活。

为了这个界面更有趣,我们要在应用中添加一些表示不同类别的 artwork。我从 Unsplash 挑选了一些 artwork,把它们放在 project11-files 文件夹下 —— 如果你已经下载好了,可以直接拖到你的 asset catalog。

Unsplash 对于图片的使用,有商业用途和非商业用途的不同 license。我添加的图片是由 Ryan Wallace, Eugene Triguba,Jamie Street,Alvaro Serrano,Joao Silas,David Dilbert 和 Casey Horner 创作的 —— 如果你需要,可以从unsplash.com获取原始图片。

接下来,创建一个叫 “DetailView” 的新 SwiftUI 视图。它只需要一个属性,即要显示的图书,添加下面这行:

let book: Book

即便只有这一行,就足以使预览代码无法编译。之前这种问题很容易修复,因为我们可以传入一个例子对象,但是当我们引入 Core Data 之后,事情稍微复杂了:创建一个新的图书对象同时也意味着我们需要有一个 managed object context。

为了解决这个问题,我们需要更新预览的代码,创建一个临时的 managed object context,然后用它来创建图书对象。

创建 managed object context 意味着我们需要引入 Core Data。把下面这行添加到 DetailView.swift 顶部,在之前的import语句之前:

import CoreData

对于预览代码,把之前的代码替换成下面这样:

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

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

        return NavigationView {
            DetailView(book: book)
        }
    }
}

如你所见,创建一个 managed object context 包括告知系统我们想要的 concurrency type。它的意思是“你想要在哪个线程访问你的数据”。对于我们的例子,使用主队列 —— 这是应用启动时采用的线程 —— 对于我们的例子足够了。

现在把注意力回到更有趣的问题:设计视图本身。我们首先把分类图片和流派放进一个ZStack,以便可以将一个叠在另一个上面。我们需要用到GeometryReader,以确保图片不会占据太多空间。我选取一些我认为不错的样式,但你自己也可以尝试任何你想要的样式。

把当前的body属性替换成下面这样:

GeometryReader { geometry in
    VStack {
        ZStack(alignment: .bottomTrailing) {
            Image(self.book.genre ?? "Fantasy")
                .frame(maxWidth: geometry.size.width)

            Text(self.book.genre?.uppercased() ?? "FANTASY")
                .font(.caption)
                .fontWeight(.black)
                .padding(8)
                .foregroundColor(.white)
                .background(Color.black.opacity(0.75))
                .clipShape(Capsule())
                .offset(x: -5, y: -5)
        }
    }
}
.navigationBarTitle(Text(book.title ?? "Unknown Book"), displayMode: .inline)

上面的代码把流派名放在ZStack的右下角,并且使用了一个背景色,粗体字,以及一些留白以凸显自己。

ZStack下方,我们要添加 review 和 rating,再加上一个 spacer ,以便所有的元素被推到视图的顶部。我们不希望用户可以这个界面调整评级,因此我们将使用另一个常量绑定,把评级视图编程只读的视图。更棒的是,由于我们采用 SF Symbols 来创建评级图像,我们可以简单地使用一个font()modifier 来放大它们,以充分利用给到我们的空间。

把下面这些视图添加到之前的ZStack下方:

Text(self.book.author ?? "Unknown author")
    .font(.title)
    .foregroundColor(.secondary)

Text(self.book.review ?? "No review")
    .padding()

RatingView(rating: .constant(Int(self.book.rating)))
    .font(.largeTitle)

Spacer()

这样一来就完成了DetailView,我们回到 ContentView.swift ,修改导航链接,让它指向正确的东西:

NavigationLink(destination: DetailView(book: book)) {

现在,再次运行应用,你应该能够点击任意图书,然后进入一个显示它们细节的新视图。


我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~