以前、こちらの記事で画像の表示方法を紹介しましたが、今回はWeb上の画像をURL指定して表示する方法を紹介します。
【SwiftUI】URL指定で画像を表示する方法【URLImage】
標準の Image にはURLを指定するイニシャライザーはありませんので、View プロトコルを継承してカスタマイズ View を作成します。
また、MVVM を意識して、View と ViewModel に分けて実装してみました。
URLImageViewModel
import SwiftUI
final class URLImageViewModel: ObservableObject {
@Published var downloadData: Data? = nil
let url: String
init(url: String, isSync: Bool = false) {
self.url = url
if isSync {
self.downloadImageSync(url: self.url)
} else {
self.downloadImageAsync(url: self.url)
}
}
func downloadImageAsync(url: String) {
guard let imageURL = URL(string: url) else {
return
}
DispatchQueue.global().async {
let data = try? Data(contentsOf: imageURL)
DispatchQueue.main.async {
self.downloadData = data
}
}
}
func downloadImageSync(url: String) {
guard let imageURL = URL(string: url) else {
return
}
let data = try? Data(contentsOf: imageURL)
self.downloadData = data
}
}
先ずは ViewModel です。
非同期で取得する場合に対応するため、画像データの変数を @Publish で宣言し、データが格納されたタイミングで View が切り替わるようにしています。
@Published var downloadData: Data?
また、同期取得・非同期取得のそれぞれのメソッドを用意して、イニシャライザーでどちらを使うか指定します(デフォルトは非同期としています)。
init(url: String, isSync: Bool = false) { ... }
func downloadImageAsync(url: String) { ... }
func downloadImageSync(url: String) { ... }
URLImageView
続いて、View 側です。
import SwiftUI
struct URLImageView: View {
@ObservedObject var viewModel: URLImageViewModel
var body: some View {
if let imageData = self.viewModel.downloadData {
if let image = UIImage(data: imageData) {
return Image(uiImage: image).resizable()
} else {
return Image(uiImage: UIImage()).resizable()
}
} else {
return Image(uiImage: UIImage()).resizable()
}
}
}
先ほど作成した URLImageViewModel を @ObservedObject 宣言で保持します。
そして、ダウンロードで取得した画像は Data 型で受け取っているので、UIImage に変換しそれを Image のイニシャライザーに指定しています。
if let image = UIImage(data: imageData) {
return Image(uiImage: image).resizable()
}
使用例
最後に、使用例を載せておきます。
struct ContentView: View {
var body: some View {
URLImageView(viewModel: .init(url: "https://www.tobezoo.com/animals/img/mn03.jpg"))
.frame(width: 256, height: 256)
.clipShape(Circle())
}
}
ちなみに、http 通信のダウンロードは iOS9 以降エラーとなってしまいますので https 通信のURLに限定しておきましょう。
どうしても http 通信で取得しなければならない場合は info.plist に例外登録をしておく必要があります。
以上
コメントを残す