AsyncImage. Loading images in SwiftUI
Note: Examples are tested on iOS 15.0 with Xcode 13.0 beta (13A5154h).
iOS 15.0 beta gives us new SwiftUI views, and one of them is AsyncImage
. It loads and displays an image from the given URL.
Let's start with a basic example:
import SwiftUI
struct ContentView: View {
private let url = URL(string: "https://picsum.photos/200")
var body: some View {
AsyncImage(url: url)
}
}
By default, it shows a gray background and replaces it with the loaded image:
Empty and success states of AsyncImage
Optionally we can change scale
to use for the image. In the example below the image size will be reduced by half:
import SwiftUI
struct ContentView: View {
private let url = URL(string: "https://picsum.photos/200")
var body: some View {
AsyncImage(url: url, scale: 2)
}
}
To update the appearance of AsyncImage, we can use an initializer with content and placeholder view builders. Here we able to modify a final image and show a custom placeholder view:
import SwiftUI
struct ContentView: View {
private let url = URL(string: "https://picsum.photos/200")
var body: some View {
AsyncImage(url: url) { image in
image
.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
Image(systemName: "photo")
.imageScale(.large)
.foregroundColor(.gray)
}
.ignoresSafeArea()
}
}
Custom placeholder and resized image
If we want to handle an error state, we can use another initializer with AsyncImagePhase
. It's a simple enum with three cases: empty, success, and error.
import SwiftUI
struct ContentView: View {
private let url = URL(string: "https://picsum.photos/200")
var body: some View {
AsyncImage(url: url, content: view)
}
@ViewBuilder
private func view(for phase: AsyncImagePhase) -> some View {
switch phase {
case .empty:
ProgressView()
case .success(let image):
image
.resizable()
.aspectRatio(contentMode: .fit)
case .failure(let error):
VStack(spacing: 16) {
Image(systemName: "xmark.octagon.fill")
.foregroundColor(.red)
Text(error.localizedDescription)
.multilineTextAlignment(.center)
}
@unknown default:
Text("Unknown")
.foregroundColor(.gray)
}
}
}
Here we show a spinner during loading, resized image if loading is successful, and an error message if something is wrong.
Working with phases of AsyncImage
To specify animations between phase changes, we can optionally add Transition
:
import SwiftUI
struct ContentView: View {
private let url = URL(string: "https://picsum.photos/200")
private let transaction: Transaction = .init(animation: .linear)
var body: some View {
AsyncImage(url: url,
transaction: transaction,
content: view)
}
...
}
And, of course, we can use AsyncImage
inside List
to show multiple images:
import SwiftUI
struct ContentView: View {
private let url = URL(string: "https://picsum.photos/200")
var body: some View {
List {
ForEach(0..<10) { _ in
AsyncImage(url: url,
content: view)
.listRowInsets(.init(.zero))
}
}
.listStyle(.plain)
}
...
}
*Finally, we can show List without separators *
If you want to play with AsyncImage
by yourself, check out AsyncImageExample project on Github.
“AsyncImage: Loading images in SwiftUI” is an informative blog post that sheds light on the efficient loading of images in SwiftUI. The use of AsyncImage allows for seamless and smooth image loading, enhancing the user experience. The visuals at https://depositphotos.com/stock-photos/gas-fireplace.html beautifully illustrate the potential applications, such as displaying captivating gas fireplace images. This blog is a valuable resource for SwiftUI developers seeking to optimize image loading and create visually stunning apps.