Reputation: 1865
I want to have an object just like AsyncImage where different states can be displayed using a "phase in" variable as in the AsyncImage example below. Can someone point me to an example on how to write an object like this? I need two features, one is using the phase variable to set the states, another is using the "let image" parameter to pass a view (in this case, an image) to the parent view. I'm not asking about the AsyncImage object, I'm using this as an example of the protocol I want to use for a custom object.
AsyncImage(
url: url,
transaction: Transaction(animation: .easeInOut)
) { phase in
switch phase {
case .empty:
ProgressView()
case .success(let image):
image
.resizable()
.transition(.scale(scale: 0.1, anchor: .center))
case .failure:
Image(systemName: "wifi.slash")
@unknown default:
EmptyView()
}
}
Upvotes: 1
Views: 251
Reputation: 30391
Here is a demo of my own version of AsyncImage
. It's definitely no-where near the full implementation, as Apple makes lots of optimisations. I also didn't add a transaction
parameter for simplicity's sake.
Code:
struct FakeAsyncImage<Content: View>: View {
enum Failure: Error {
case missingURL
case invalidImage
}
@State private var phase: AsyncImagePhase = .empty
private let url: URL?
private let scale: CGFloat
private let content: (AsyncImagePhase) -> Content
init(url: URL?, scale: CGFloat = 1, @ViewBuilder content: @escaping (AsyncImagePhase) -> Content) {
self.url = url
self.scale = scale
self.content = content
}
var body: some View {
content(phase)
.task {
await makeRequest()
}
}
private func makeRequest() async {
guard let url = url else {
phase = .failure(Failure.missingURL)
return
}
do {
let (data, _) = try await URLSession.shared.data(from: url)
guard let uiImage = UIImage(data: data, scale: scale) else {
phase = .failure(Failure.invalidImage)
return
}
phase = .success(Image(uiImage: uiImage))
} catch {
phase = .failure(error)
}
}
}
Example usage:
struct ContentView: View {
var body: some View {
FakeAsyncImage(url: URL(string: "https://www.gravatar.com/avatar/e527532a57601f0f368f6643317be841?s=256&d=identicon&r=PG&f=1")) { phase in
switch phase {
case .empty:
ProgressView()
case .success(let image):
image
.resizable()
.transition(.scale(scale: 0.1))
case .failure:
Image(systemName: "wifi.slash")
@unknown default:
EmptyView()
}
}
}
}
Upvotes: 1