SwiftUIでURLから画像を取得して表示する方法

画像出典:Appleサイトよりスクリーンショット

SwiftUIでURLから画像を取得して表示する方法を紹介します。

指定されたURLから画像をダウンロードする ImageLoader と、その画像を表示する URLImage を作成すると表示することができます。

まず画像をダウンロードする ImageLoader です。

class ImageLoader: ObservableObject {
    let objectWillChange = ObservableObjectPublisher()

    var image: Image? {
        willSet {
            objectWillChange.send()
        }
    }

    func load(url: String) {
        guard let url = URL(string: url) else { return }
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data, let image = UIImage(data: data) else { return }
            DispatchQueue.main.async {
                self.image = Image(uiImage: image)
            }
        }.resume()
    }
}

ObservableObjectにして、imageの変更を監視できるようにします。load関数で指定されたURLから画像をダウンロードしてImageをセットします。

次に画像を表示するView URLImage です。

struct URLImage<Content>: View where Content: View {
    @ObservedObject var imageLoader = ImageLoader()

    private let url: String
    private let content: (_ image: Image) -> Content

    init(url: String, content: @escaping (_ image: Image) -> Content) {
        self.url = url
        self.content = content
    }

    var body: some View {
        ZStack {
            if imageLoader.image != nil {
                content(imageLoader.image!)
            } else {
                content(Image("placeholder"))
            }
        }.onAppear {
            self.imageLoader.load(url: self.url)
        }
    }
}

struct URLImage_Previews: PreviewProvider {
    static var previews: some View {
        URLImage(url: "") {
            $0
        }
    }
}

urlを受け取りonAppearImageLoaderloadを呼び出します。ここではダウンロードする前でimagenilの時はplaceholder画像を表示するようにしています。

またcontentを受け取ることで、URLImageを呼び出した側から画像のスタイルを変更できるようにできます。

URLImageの使い方です。例えば、画像を丸い円でクリップして影をつけてみます。

URLImage(url: url) {
    $0.renderingMode(.original)
        .resizable()
        .scaledToFit()
        .clipShape(Circle())
        .frame(width: 50.0, height: 50.0)
        .overlay(Circle().stroke(Color.white,lineWidth:4).shadow(radius: 10))
}

画像

より使いやすいAPIを提供してくれているOSSもすでにGitHubに公開されています。

dmytro-anokhin/url-image

エンジニアリング SwiftUI 画像


関連記事