我想确保在下载图像时ProgressView
是可见的,如果传递的url无效(空(,则会放置占位符。
我该怎么做?
代码:
import Foundation
import SwiftUI
// Download image from URL
struct NetworkImage: View {
public let url: URL?
var body: some View {
Group {
if let url = url, let imageData = try? Data(contentsOf: url),
let uiImage = UIImage(data: imageData) {
Image(uiImage: uiImage)
.resizable()
.aspectRatio(contentMode: .fill)
}
else {
ProgressView()
}
}
}
}
struct NetworkImage_Previews: PreviewProvider {
static var previews: some View {
let url = [
"",
"http://google.com",
"https://yt3.ggpht.com/a/AATXAJxAbUTyYnKsycQjZzCdL_gWVbJYVy4mVaVGQ8kRMQ=s176-c-k-c0x00ffffff-no-rj"
]
NetworkImage(url: URL(string: url[0])!)
}
}
您可以创建一个ViewModel
来处理下载逻辑:
extension NetworkImage {
class ViewModel: ObservableObject {
@Published var imageData: Data?
@Published var isLoading = false
private var cancellables = Set<AnyCancellable>()
func loadImage(from url: URL?) {
isLoading = true
guard let url = url else {
isLoading = false
return
}
URLSession.shared.dataTaskPublisher(for: url)
.map { $0.data }
.replaceError(with: nil)
.receive(on: DispatchQueue.main)
.sink { [weak self] in
self?.imageData = $0
self?.isLoading = false
}
.store(in: &cancellables)
}
}
}
并修改您的NetworkImage
以显示占位符图像:
struct NetworkImage: View {
@StateObject private var viewModel = ViewModel()
let url: URL?
var body: some View {
Group {
if let data = viewModel.imageData, let uiImage = UIImage(data: data) {
Image(uiImage: uiImage)
.resizable()
.aspectRatio(contentMode: .fill)
} else if viewModel.isLoading {
ProgressView()
} else {
Image(systemName: "photo")
}
}
.onAppear {
viewModel.loadImage(from: url)
}
}
}
然后你可以像这样使用它:
NetworkImage(url: URL(string: "https://stackoverflow.design/assets/img/logos/so/logo-stackoverflow.png"))
(请注意,url
参数是而不是力展开(。