From 35190d2c0a79bfc100bd358cc410b67082a1ce06 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 5 Oct 2019 15:39:30 +0800 Subject: [PATCH 1/4] Using binding to support the animation control. This API design is the same as SwiftUI's Toggle/Sheet --- SDWebImageSwiftUI/Classes/AnimatedImage.swift | 71 ++++++++++++------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index 89c3442b..08232962 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -48,6 +48,46 @@ public struct AnimatedImage : PlatformViewRepresentable { var webOptions: SDWebImageOptions = [] var webContext: [SDWebImageContextOption : Any]? = nil + /// A Binding to control the animation. You can bind external logic to control the animation status. + /// True to start animation, false to stop animation. + @Binding public var isAnimating: Bool + + public init(url: URL?, placeholder: PlatformImage? = nil, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil) { + self.init(url: url, placeholder: placeholder, options: options, context: context, isAnimating: .constant(true)) + } + + public init(url: URL?, placeholder: PlatformImage? = nil, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil, isAnimating: Binding) { + self._isAnimating = isAnimating + self.placeholder = placeholder + self.webOptions = options + self.webContext = context + self.imageModel.url = url + } + + public init(name: String, bundle: Bundle? = nil) { + self.init(name: name, bundle: bundle, isAnimating: .constant(true)) + } + + public init(name: String, bundle: Bundle? = nil, isAnimating: Binding) { + self._isAnimating = isAnimating + #if os(macOS) + let image = SDAnimatedImage(named: name, in: bundle) + #else + let image = SDAnimatedImage(named: name, in: bundle, compatibleWith: nil) + #endif + self.imageModel.image = image + } + + public init(data: Data, scale: CGFloat = 0) { + self.init(data: data, scale: scale, isAnimating: .constant(true)) + } + + public init(data: Data, scale: CGFloat = 0, isAnimating: Binding) { + self._isAnimating = isAnimating + let image = SDAnimatedImage(data: data, scale: scale) + self.imageModel.image = image + } + #if os(macOS) public typealias NSViewType = AnimatedImageViewWrapper #else @@ -89,6 +129,13 @@ public struct AnimatedImage : PlatformViewRepresentable { } } } + if self.isAnimating != view.wrapped.isAnimating { + if self.isAnimating { + view.wrapped.startAnimating() + } else { + view.wrapped.stopAnimating() + } + } configureView(view, context: context) layoutView(view, context: context) @@ -310,30 +357,6 @@ extension AnimatedImage { } } -// Initializer -extension AnimatedImage { - public init(url: URL?, placeholder: PlatformImage? = nil, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil) { - self.placeholder = placeholder - self.webOptions = options - self.webContext = context - self.imageModel.url = url - } - - public init(name: String, bundle: Bundle? = nil) { - #if os(macOS) - let image = SDAnimatedImage(named: name, in: bundle) - #else - let image = SDAnimatedImage(named: name, in: bundle, compatibleWith: nil) - #endif - self.imageModel.image = image - } - - public init(data: Data, scale: CGFloat = 0) { - let image = SDAnimatedImage(data: data, scale: scale) - self.imageModel.image = image - } -} - #if DEBUG struct AnimatedImage_Previews : PreviewProvider { static var previews: some View { From 25871610690af85defbd8ccc0f7340cd7684ee50 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 5 Oct 2019 15:43:52 +0800 Subject: [PATCH 2/4] Update the example to show how to use animation control with Binding --- Example/SDWebImageSwiftUIDemo/DetailView.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Example/SDWebImageSwiftUIDemo/DetailView.swift b/Example/SDWebImageSwiftUIDemo/DetailView.swift index 3455fb35..ccdc2c87 100644 --- a/Example/SDWebImageSwiftUIDemo/DetailView.swift +++ b/Example/SDWebImageSwiftUIDemo/DetailView.swift @@ -13,6 +13,7 @@ struct DetailView: View { let url: String let animated: Bool @State var progress: CGFloat = 1 + @State var isAnimating: Bool = true var body: some View { VStack { @@ -24,7 +25,7 @@ struct DetailView: View { Spacer() HStack { if animated { - AnimatedImage(url: URL(string:url), options: [.progressiveLoad]) + AnimatedImage(url: URL(string:url), options: [.progressiveLoad], isAnimating: $isAnimating) .onProgress(perform: { (receivedSize, expectedSize) in // SwiftUI engine itself ensure the main queue dispatch if (expectedSize >= 0) { @@ -35,6 +36,9 @@ struct DetailView: View { }) .resizable() .scaledToFit() + .navigationBarItems(trailing: Button(isAnimating ? "Stop" : "Start") { + self.isAnimating.toggle() + }) } else { WebImage(url: URL(string:url), options: [.progressiveLoad]) .onProgress(perform: { (receivedSize, expectedSize) in From b62cbdf0721ed816929b06fd68bec1ae1a8c5265 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 5 Oct 2019 15:49:16 +0800 Subject: [PATCH 3/4] Fix the compile issue of macOS --- SDWebImageSwiftUI/Classes/AnimatedImage.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index 08232962..747464a8 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -129,6 +129,12 @@ public struct AnimatedImage : PlatformViewRepresentable { } } } + + #if os(macOS) + if self.isAnimating != view.wrapped.animates { + view.wrapped.animates = self.isAnimating + } + #else if self.isAnimating != view.wrapped.isAnimating { if self.isAnimating { view.wrapped.startAnimating() @@ -136,6 +142,7 @@ public struct AnimatedImage : PlatformViewRepresentable { view.wrapped.stopAnimating() } } + #endif configureView(view, context: context) layoutView(view, context: context) From bcb871a085b2f550ca5ff6f14600cf63340b3ccc Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 5 Oct 2019 15:52:56 +0800 Subject: [PATCH 4/4] Update the readme about the animation control binding --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 290f42c5..85ffa5fc 100644 --- a/README.md +++ b/README.md @@ -85,20 +85,24 @@ var body: some View { ```swift var body: some View { Group { - AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif")) // Network + // Network + AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif")) .onFailure(perform: { (error) in // Error }) .scaledToFit() - AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp"))) // Data + // Data + AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp"))) .customLoopCount(1) - AnimatedImage(name: "animation1") // Bundle (not Asset Catalog) + // Bundle (not Asset Catalog) + AnimatedImage(name: "animation1", isAnimating: $isAnimating)) // Animation control binding .maxBufferSize(.max) } } ``` - [x] Supports network image as well as local data and bundle image +- [x] Supports animation control using the SwiftUI Binding - [x] Supports advanced control like loop count, incremental load, buffer size. Note: `AnimatedImage` supports both image url or image data for animated image format. Which use the SDWebImage's [Animated ImageView](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#animated-image-50) for internal implementation.