在 WWDC 2021 中,Apple 公布了 SwiftUI 框架的大量新功能,使开发者的开发 App 变得更得心应手。 AsyncImage
绝对是 iOS 15 其中一个最令人期待的功能。如果你的App需要从远程服务器加载和显示图像,这个新视图应该可以让你不必编写自己的代码来处理非同步 (asynchronous) 下载。
AsyncImage
是用于非同步加载和显示远程图像的内置视图。 你只需要告诉它图像的 URL, AsyncImage
就自动抓取远程图像并将其显示在屏幕上。
在本章中,我将向你讲解如何在 SwiftUI 项目中使用 AsyncImage
。
使用 AsyncImage 的最简单方法是像这样指定图像的 URL:
AsyncImage(url: URL(string: imageURL))
AsyncImage 就会自动连接到所指定的 URL 以非同步形式从远程服务器加载图像。 当图像尚未能够显示时,它还会自动将占位符呈现为灰色。 完全下载后,AsyncImage
就会以其固有大小显示图像。
假设你已经在 Xcode 中建立了一个新的 SwiftUI 项目,你可以像这样修改 ContentView
中的代码来试一试:
struct ContentView: View {
let imageURL = "https://link.appcoda.com/testimage"
var body: some View {
AsyncImage(url: URL(string: imageURL))
}
}
修改后,你应该会看到一个灰色的占位符。数秒后,就会显示下载的图像。
如果要使图像变小或变大,可以将缩放值传给 scale
参数,如下所示:
AsyncImage(url: URL(string: imageURL), scale: 2.0)
要缩小图像,你就指定一个大于 1.0 的值。 相反,小于 1 的值就会把图像变大。
AsyncImage
也提供了另一个构造函数 (constructor),让开发者可以进一步客制化图像:
init<I, P>(url: URL?, scale: CGFloat, content: (Image) -> I, placeholder: () -> P)
我们可以使用上面的 init
初始化 AsyncImage
,来调整及缩放下载好的图像。更重要的是,我们可以实现自己的占位符。看看以下的示例代码片段:
AsyncImage(url: URL(string: imageURL)) { image in
image
.resizable()
.scaledToFill()
} placeholder: {
Color.purple.opacity(0.1)
}
.frame(width: 300, height: 500)
.cornerRadius(20)
在上面的代码中,AsyncImage
提供了下载好的图像。然后,我们应用 resizable()
和 scaledToFill()
修饰符来调整图像尺寸,并把 AsyncImage
视图的尺寸限制为 300×500 points。
placeholder
参数让我们可以创建自己的占位符,来取代默认的占位符。在以下示例中,我们把占位符设置为浅紫色。
如果你需要更精准操作非同步下载,AsyncImage
视图提供了另一个init
函数:
init(url: URL?, scale: CGFloat, transaction: Transaction, content: (AsyncImagePhase) -> Content
AsyncImagePhase
是一个枚举 (enum),用于跟踪下载操作的当前阶段。 你可以针对每个阶段提供详细的实现,包括empty、failure 和success。
看看以下示例代码片段:
AsyncImage(url: URL(string: imageURL)) { phase in
switch phase {
case .empty:
Color.purple.opacity(0.1)
case .success(let image):
image
.resizable()
.scaledToFill()
case .failure(_):
Image(systemName: "exclamationmark.icloud")
.resizable()
.scaledToFit()
@unknown default:
Image(systemName: "exclamationmark.icloud")
}
}
.frame(width: 300, height: 300)
.cornerRadius(20)
在 Empty 的情况下,表示图像未加载,于是我们会显示一个占位符。在 success 的情况下,我们就会应用几个修饰符,并将图像显示在屏幕上。在 failure 的情况下,我们就可以在出现错误时提供备用视图 (alternate view)。在上面的代码中,我们就这样显示了一个系统图像。
同一个 init
可以让我们在阶段修改时指定可选 transaction
。例如,以下代码片段在 transaction
参数中指定使用 spring
类型的动画:
AsyncImage(url: URL(string: imageURL), transaction: Transaction(animation: .spring())) { phase in
switch phase {
case .empty:
Color.purple.opacity(0.1)
case .success(let image):
image
.resizable()
.scaledToFill()
case .failure(_):
Image(systemName: "exclamationmark.icloud")
.resizable()
.scaledToFit()
@unknown default:
Image(systemName: "exclamationmark.icloud")
}
}
.frame(width: 300, height: 500)
.cornerRadius(20)
如此一来,在下载图像后,我们就会看到淡入 (fade-in) 动画。我们无法在预览版面中测试代码,请在模拟器中测试代码以查看动画。
你也可以把 transition
修饰符附加到 image
视图:
case .success(let image):
image
.resizable()
.scaledToFill()
.transition(.slide)
这样在显示结果图像时,就会看到滑入 (slide-in) 动画。
在本章中,我们介绍了一个非常好用的“AsyncImage”视图。有了这个新功能,下载和显示远程图像(Remote Image)时都变得非常容易。 你只需要指定图像的 URL,AsyncImage视图就会为你完成所有繁重的工作。
在本章所准备的示例档中,有最后完整的 Xcode 项目,可供你下载参考:
https://www.appcoda.com/resources/swiftui4/SwiftUIAsyncImage.zip