onevcat / Kingfisher

A lightweight, pure-Swift library for downloading and caching images from the web.
MIT License
23.11k stars 2.64k forks source link

Add `KFImageView` for SwiftUI #1408

Open sindresorhus opened 4 years ago

sindresorhus commented 4 years ago

Check List

Thanks for considering to open an issue. Before you submit your issue, please confirm these boxes are checked.

Issue Description

Thanks for providing such a high-quality library 🙌

KFImage is very convenient for still images, but my SwiftUI-based macOS app needs to show animated GIFs, so I cannot use KFImage because SwiftUI Image doesn't support animated GIFs. It would be very useful if Kingfisher could also provide a KFImageView view. It would be almost the same as KFImage, but would use something like the following internally instead of Image:

struct KFImageView: NSViewRepresentable {
    typealias NSViewType = NSImageView

    let resource: ImageResource
    var options: KingfisherOptionsInfo?
    var isLoaded: Binding<Bool>?
    var animates = true
    var imageScaling: NSImageScaling = .scaleProportionallyDown

    func makeNSView(context: Context) -> NSViewType {
        let nsView = NSViewType()
        nsView.wantsLayer = true
        nsView.translatesAutoresizingMaskIntoConstraints = false
        nsView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
        nsView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        return nsView
    }

    func updateNSView(_ nsView: NSViewType, context: Context) {
        nsView.imageScaling = imageScaling
        nsView.animates = animates

        nsView.kf.setImage(with: resource, options: options) { _ in
            DispatchQueue.main.async {
                self.isLoaded?.wrappedValue = true
            }
        }
    }
}

extension KFImageView {
    init(
        url: URL,
        options: KingfisherOptionsInfo? = nil,
        isLoaded: Binding<Bool>? = nil,
        animates: Bool = true,
        imageScaling: NSImageScaling = .scaleProportionallyDown
    ) {
        let resource = ImageResource(downloadURL: url)

        self.init(
            resource: resource,
            options: options,
            isLoaded: isLoaded,
            animates: animates,
            imageScaling: imageScaling
        )
    }
}
sindresorhus commented 4 years ago

For reference, SDWebImageSwiftUI has a separate SwiftUI wrapper for animated images too: https://github.com/SDWebImage/SDWebImageSwiftUI#using-animatedimage-to-play-animation

codetheweb commented 4 years ago

@onevcat any opinion on this? I would really appreciate GIF support as well.

wilg commented 3 years ago

This would be great @onevcat, especially since SDWebImageSwiftUI's animation support seems pretty broken right now.