Learn how to work with Xcode Previews in SwiftData App. SwiftData in combination with SwiftUI…
AsyncImage in SwiftUI
SwiftUI’s AsyncImage
view simplifies the process of loading and displaying remote images asynchronously. It provides built-in support for placeholders and error handling, making it an essential tool for modern app development. This tutorial will guide you through the basics and demonstrate unique examples that cater to developers of all levels.
Introduction to AsyncImage
AsyncImage
is a view that asynchronously loads and displays an image from a specified URL. You can easily add a placeholder, handle errors, and manipulate the loaded image.
Basic Usage of AsyncImage
Let’s start with a basic example of loading an image from a URL and displaying it in a SwiftUI view.
import SwiftUI
struct BasicAsyncImageView: View {
let imageUrl = URL(string: "https://picsum.photos/200")
var body: some View {
AsyncImage(url: imageUrl)
.frame(width: 200, height: 200)
}
}
In this example, we load an image from a URL and display it within a 200×200 frame. Until the image loads, SwiftUI displays a default placeholder.
Customizing the Placeholder
You can customize the placeholder to enhance the user experience while the image is loading.
import SwiftUI
struct PlaceholderAsyncImageView: View {
let imageUrl = URL(string: "https://picsum.photos/200")
var body: some View {
AsyncImage(url: imageUrl) { image in
image
.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
ProgressView("Loading...")
.frame(width: 200, height: 200)
}
}
}
Here, we use ProgressView
as a custom placeholder, which is displayed until the image is fully loaded.
Handling Errors
It’s crucial to handle errors gracefully, providing a fallback UI when the image fails to load.
import SwiftUI
struct ErrorHandlingAsyncImageView: View {
let imageUrl = URL(string: "https://picsum.photos/200")
var body: some View {
AsyncImage(url: imageUrl) { phase in
switch phase {
case .empty:
ProgressView("Loading...")
.frame(width: 200, height: 200)
case .success(let image):
image
.resizable()
.aspectRatio(contentMode: .fit)
case .failure:
Image(systemName: "exclamationmark.triangle")
.resizable()
.frame(width: 50, height: 50)
.foregroundColor(.red)
@unknown default:
EmptyView()
}
}
.frame(width: 200, height: 200)
}
}
In this example, we handle different loading phases using a switch statement. If the image fails to load, we display a system symbol as an error indicator.
Advanced Example: Image Grid
Let’s create an advanced example where we display a grid of asynchronously loaded images.
import SwiftUI
struct ImageGridAsyncView: View {
let urls = [
URL(string: "https://picsum.photos/200/300"),
URL(string: "https://picsum.photos/200"),
URL(string: "https://picsum.photos/300"),
URL(string: "https://picsum.photos/400")
]
var body: some View {
let columns = [
GridItem(.flexible()),
GridItem(.flexible())
]
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(urls, id: \.self) { url in
AsyncImage(url: url) { phase in
switch phase {
case .empty:
ProgressView()
.frame(width: 100, height: 100)
case .success(let image):
image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100)
.clipped()
case .failure:
Image(systemName: "exclamationmark.triangle")
.resizable()
.frame(width: 50, height: 50)
.foregroundColor(.red)
@unknown default:
EmptyView()
}
}
}
}
.padding()
}
}
}