Skip to content

Commit 33c11b1

Browse files
committed
Refactory the pure SwiftUI AnimatedImage implementation, right in the WebImage view.
Support watchOS as well :) Good SwiftUI
1 parent 5843483 commit 33c11b1

File tree

4 files changed

+91
-12
lines changed

4 files changed

+91
-12
lines changed

Example/SDWebImageSwiftUIDemo/ContentView.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct ContentView: View {
3838
"https://raw.githubusercontent.com/icons8/flat-color-icons/master/pdf/stack_of_photos.pdf",
3939
"https://raw.githubusercontent.com/icons8/flat-color-icons/master/pdf/smartphone_tablet.pdf"
4040
]
41-
@State var animated: Bool = false // You can change between WebImage/AnimatedImage
41+
@State var animated: Bool = true // You can change between WebImage/AnimatedImage
4242

4343
var body: some View {
4444
#if os(iOS) || os(tvOS)
@@ -105,8 +105,16 @@ struct ContentView: View {
105105
.scaledToFit()
106106
.frame(width: CGFloat(100), height: CGFloat(100), alignment: .center)
107107
#else
108-
AnimatedImage(url: URL(string:url))
108+
WebImage(url: URL(string:url))
109109
.resizable()
110+
.animated()
111+
.indicator { _, _ in
112+
ActivityBar()
113+
.foregroundColor(Color.white)
114+
.frame(width: 50, height: 50)
115+
}
116+
.animation(.easeInOut(duration: 0.5))
117+
.transition(.fade)
110118
.scaledToFit()
111119
.frame(width: CGFloat(100), height: CGFloat(100), alignment: .center)
112120
#endif

Example/SDWebImageSwiftUIDemo/DetailView.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,14 @@ struct DetailView: View {
9595
.resizable()
9696
.scaledToFit()
9797
#else
98-
AnimatedImage(url: URL(string:url), options: [.progressiveLoad], isAnimating: $isAnimating)
98+
WebImage(url: URL(string:url), options: [.progressiveLoad])
9999
.resizable()
100+
.animated(isAnimating)
101+
.indicator { isAnimating, progress in
102+
ProgressBar(value: progress)
103+
.foregroundColor(.blue)
104+
.frame(maxHeight: 6)
105+
}
100106
.scaledToFit()
101107
#endif
102108
} else {

SDWebImageSwiftUI/Classes/WebImage.swift

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ import SDWebImage
1111

1212
/// A Image View type to load image from url. Supports static image format.
1313
public struct WebImage : View {
14-
var url: URL?
15-
var options: SDWebImageOptions
16-
var context: [SDWebImageContextOption : Any]?
17-
1814
var configurations: [(Image) -> Image] = []
1915

2016
var placeholder: AnyView?
@@ -23,14 +19,16 @@ public struct WebImage : View {
2319

2420
@ObservedObject var imageManager: ImageManager
2521

22+
// Animated Image support (Beta)
23+
var animated: Bool = false
24+
@State var currentFrame: PlatformImage? = nil
25+
@State var imagePlayer: SDAnimatedImagePlayer? = nil
26+
2627
/// Create a web image with url, placeholder, custom options and context.
2728
/// - Parameter url: The image url
2829
/// - Parameter options: The options to use when downloading the image. See `SDWebImageOptions` for the possible values.
2930
/// - Parameter context: A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
3031
public init(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil) {
31-
self.url = url
32-
self.options = options
33-
self.context = context
3432
self.imageManager = ImageManager(url: url, options: options, context: context)
3533
// load remote image here, SwiftUI sometimes will create a new View struct without calling `onAppear` (like enter EditMode) :)
3634
// this can ensure we load the image, SDWebImage take care of the duplicated query
@@ -40,8 +38,29 @@ public struct WebImage : View {
4038
public var body: some View {
4139
Group {
4240
if imageManager.image != nil {
43-
configurations.reduce(Image(platformImage: imageManager.image!)) { (previous, configuration) in
44-
configuration(previous)
41+
if animated {
42+
if currentFrame != nil {
43+
configurations.reduce(Image(platformImage: currentFrame!)) { (previous, configuration) in
44+
configuration(previous)
45+
}
46+
.onAppear {
47+
self.imagePlayer?.startPlaying()
48+
}
49+
.onDisappear {
50+
self.imagePlayer?.pausePlaying()
51+
}
52+
} else {
53+
configurations.reduce(Image(platformImage: imageManager.image!)) { (previous, configuration) in
54+
configuration(previous)
55+
}
56+
.onReceive(imageManager.$image) { image in
57+
self.setupPlayer(image: image)
58+
}
59+
}
60+
} else {
61+
configurations.reduce(Image(platformImage: imageManager.image!)) { (previous, configuration) in
62+
configuration(previous)
63+
}
4564
}
4665
} else {
4766
Group {
@@ -194,6 +213,51 @@ extension WebImage {
194213
}
195214
}
196215

216+
// Animated Image support (Beta)
217+
extension WebImage {
218+
219+
/// Make the image to support animated images. The animation will start when view appears, and pause when disappears.
220+
/// - Note: Currently we do not have advanced control like binding, reset frame index, playback rate, etc. For those use case, it's recommend to use `AnimatedImage` type instead. (support iOS/tvOS/macOS)
221+
/// - Warning: This API need polishing. In the future we may choose to create a new View type instead.
222+
///
223+
/// - Parameter animated: Whether or not to enable animationn.
224+
public func animated(_ animated: Bool = true) -> WebImage {
225+
var result = self
226+
result.animated = animated
227+
if animated {
228+
// Update Image Manager
229+
result.imageManager.cancel()
230+
var context = result.imageManager.context ?? [:]
231+
context[.animatedImageClass] = SDAnimatedImage.self
232+
result.imageManager.context = context
233+
result.imageManager.load()
234+
} else {
235+
// Update Image Manager
236+
result.imageManager.cancel()
237+
var context = result.imageManager.context ?? [:]
238+
context[.animatedImageClass] = nil
239+
result.imageManager.context = context
240+
result.imageManager.load()
241+
}
242+
return result
243+
}
244+
245+
func setupPlayer(image: PlatformImage?) {
246+
if imagePlayer != nil {
247+
return
248+
}
249+
if let animatedImage = image as? SDAnimatedImageProvider {
250+
if let imagePlayer = SDAnimatedImagePlayer(provider: animatedImage) {
251+
imagePlayer.animationFrameHandler = { (_, frame) in
252+
self.currentFrame = frame
253+
}
254+
self.imagePlayer = imagePlayer
255+
imagePlayer.startPlaying()
256+
}
257+
}
258+
}
259+
}
260+
197261
#if DEBUG
198262
struct WebImage_Previews : PreviewProvider {
199263
static var previews: some View {

SDWebImageSwiftUI/Module/SDWebImageSwiftUI.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ FOUNDATION_EXPORT double SDWebImageSwiftUIVersionNumber;
1515
FOUNDATION_EXPORT const unsigned char SDWebImageSwiftUIVersionString[];
1616

1717
// In this header, you should import all the public headers of your framework using statements like #import <SDWebImageSwiftUI/PublicHeader.h>
18+
#import <SDWebImage/SDWebImage.h>

0 commit comments

Comments
 (0)