Skip to content

Supports AnimatedImage animation control using of SwiftUI Binding #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Example/SDWebImageSwiftUIDemo/DetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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) {
Expand All @@ -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
Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
78 changes: 54 additions & 24 deletions SDWebImageSwiftUI/Classes/AnimatedImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Bool>) {
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<Bool>) {
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<Bool>) {
self._isAnimating = isAnimating
let image = SDAnimatedImage(data: data, scale: scale)
self.imageModel.image = image
}

#if os(macOS)
public typealias NSViewType = AnimatedImageViewWrapper
#else
Expand Down Expand Up @@ -90,6 +130,20 @@ 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()
} else {
view.wrapped.stopAnimating()
}
}
#endif

configureView(view, context: context)
layoutView(view, context: context)
}
Expand Down Expand Up @@ -310,30 +364,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 {
Expand Down