@@ -12,11 +12,6 @@ import SDWebImage
12
12
import SDWebImageSwiftUIObjC
13
13
#endif
14
14
15
- // Data Binding Object
16
- final class AnimatedImageModel : ObservableObject {
17
- @Published var image : PlatformImage ?
18
- }
19
-
20
15
// Convenient
21
16
#if os(watchOS)
22
17
public typealias AnimatedImageViewWrapper = SDAnimatedImageInterface
@@ -39,10 +34,9 @@ public final class AnimatedImageCoordinator: NSObject {
39
34
40
35
// View
41
36
public struct AnimatedImage : PlatformViewRepresentable {
42
- @ObservedObject var imageModel = AnimatedImageModel ( )
43
-
44
37
// Options
45
38
var url : URL ?
39
+ @State var image : PlatformImage ?
46
40
var webOptions : SDWebImageOptions = [ ]
47
41
var webContext : [ SDWebImageContextOption : Any ] ? = nil
48
42
@@ -64,6 +58,10 @@ public struct AnimatedImage : PlatformViewRepresentable {
64
58
var incrementalLoad : Bool ?
65
59
var maxBufferSize : UInt ?
66
60
var customLoopCount : Int ?
61
+ var runLoopMode : RunLoop . Mode ?
62
+ var pausable : Bool ?
63
+ var purgeable : Bool ?
64
+ var playBackRate : Double ?
67
65
#if os(macOS) || os(iOS) || os(tvOS)
68
66
// These configurations only useful for web image loading
69
67
var indicator : SDWebImageIndicator ?
@@ -80,11 +78,6 @@ public struct AnimatedImage : PlatformViewRepresentable {
80
78
/// True to start animation, false to stop animation.
81
79
@Binding public var isAnimating : Bool
82
80
83
- /// Current loaded image, may be `SDAnimatedImage` type
84
- public var image : PlatformImage ? {
85
- imageModel. image
86
- }
87
-
88
81
/// Create an animated image with url, placeholder, custom options and context.
89
82
/// - Parameter url: The image url
90
83
/// - Parameter placeholder: The placeholder image to show during loading
@@ -127,7 +120,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
127
120
#else
128
121
let image = SDAnimatedImage ( named: name, in: bundle, compatibleWith: nil )
129
122
#endif
130
- self . imageModel . image = image
123
+ self . image = image
131
124
}
132
125
133
126
/// Create an animated image with data and scale.
@@ -144,7 +137,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
144
137
public init ( data: Data , scale: CGFloat = 0 , isAnimating: Binding < Bool > ) {
145
138
self . _isAnimating = isAnimating
146
139
let image = SDAnimatedImage ( data: data, scale: scale)
147
- self . imageModel . image = image
140
+ self . image = image
148
141
}
149
142
150
143
#if os(macOS)
@@ -208,8 +201,10 @@ public struct AnimatedImage : PlatformViewRepresentable {
208
201
view. wrapped. sd_setImage ( with: url, placeholderImage: placeholder, options: webOptions, context: webContext, progress: { ( receivedSize, expectedSize, _) in
209
202
self . progressBlock ? ( receivedSize, expectedSize)
210
203
} ) { ( image, error, cacheType, _) in
204
+ DispatchQueue . main. async {
205
+ self . image = image
206
+ }
211
207
if let image = image {
212
- self . imageModel. image = image
213
208
self . successBlock ? ( image, cacheType)
214
209
} else {
215
210
self . failureBlock ? ( error ?? NSError ( ) )
@@ -226,12 +221,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
226
221
}
227
222
228
223
func updateView( _ view: AnimatedImageViewWrapper , context: Context ) {
229
- // macOS SDAnimatedImageView.animates should initialize to true in advance before set image
230
- #if os(macOS)
231
- view. wrapped. animates = true
232
- #endif
233
-
234
- if let image = self . imageModel. image {
224
+ if let image = self . image {
235
225
#if os(watchOS)
236
226
view. wrapped. setImage ( image)
237
227
#else
@@ -248,7 +238,9 @@ public struct AnimatedImage : PlatformViewRepresentable {
248
238
}
249
239
250
240
#if os(macOS)
251
- view. wrapped. animates = self . isAnimating
241
+ if self . isAnimating != view. wrapped. animates {
242
+ view. wrapped. animates = self . isAnimating
243
+ }
252
244
#else
253
245
if self . isAnimating != view. wrapped. isAnimating {
254
246
if self . isAnimating {
@@ -338,17 +330,15 @@ public struct AnimatedImage : PlatformViewRepresentable {
338
330
339
331
#if os(macOS)
340
332
view. wrapped. imageScaling = contentMode
341
- #elseif os(iOS) || os(tvOS)
333
+ #else
342
334
view. wrapped. contentMode = contentMode
343
- #elseif os(watchOS)
344
- view. wrapped. setContentMode ( contentMode)
345
335
#endif
346
336
347
337
// Animated Image does not support resizing mode and rendering mode
348
- if let image = self . imageModel . image, !image. sd_isAnimated, !image. conforms ( to: SDAnimatedImageProtocol . self) {
338
+ if let image = self . image, !image. sd_isAnimated, !image. conforms ( to: SDAnimatedImageProtocol . self) {
349
339
var image = image
350
340
// ResizingMode
351
- if let resizingMode = self . resizingMode {
341
+ if let resizingMode = self . resizingMode, capInsets != EdgeInsets ( ) {
352
342
#if os(macOS)
353
343
let capInsets = NSEdgeInsets ( top: self . capInsets. top, left: self . capInsets. leading, bottom: self . capInsets. bottom, right: self . capInsets. trailing)
354
344
#else
@@ -467,12 +457,40 @@ public struct AnimatedImage : PlatformViewRepresentable {
467
457
}
468
458
#elseif os(watchOS)
469
459
if let customLoopCount = self . customLoopCount {
470
- view. wrapped. setAnimationRepeatCount ( customLoopCount as NSNumber )
460
+ view. wrapped. animationRepeatCount = customLoopCount as NSNumber
471
461
} else {
472
462
// disable custom loop count
473
- view. wrapped. setAnimationRepeatCount ( nil )
463
+ view. wrapped. animationRepeatCount = nil
474
464
}
475
465
#endif
466
+
467
+ // RunLoop Mode
468
+ if let runLoopMode = self . runLoopMode {
469
+ view. wrapped. runLoopMode = runLoopMode
470
+ } else {
471
+ view. wrapped. runLoopMode = . common
472
+ }
473
+
474
+ // Pausable
475
+ if let pausable = self . pausable {
476
+ view. wrapped. resetFrameIndexWhenStopped = !pausable
477
+ } else {
478
+ view. wrapped. resetFrameIndexWhenStopped = false
479
+ }
480
+
481
+ // Clear Buffer
482
+ if let purgeable = self . purgeable {
483
+ view. wrapped. clearBufferWhenStopped = purgeable
484
+ } else {
485
+ view. wrapped. clearBufferWhenStopped = false
486
+ }
487
+
488
+ // Playback Rate
489
+ if let playBackRate = self . playBackRate {
490
+ view. wrapped. playbackRate = playBackRate
491
+ } else {
492
+ view. wrapped. playbackRate = 1.0
493
+ }
476
494
}
477
495
}
478
496
@@ -625,6 +643,47 @@ extension AnimatedImage {
625
643
result. incrementalLoad = incrementalLoad
626
644
return result
627
645
}
646
+
647
+ /// The runLoopMode when animation is playing on. Defaults is `.common`
648
+ /// You can specify a runloop mode to let it rendering.
649
+ /// - Note: This is useful for some cases, for example, always specify NSDefaultRunLoopMode, if you want to pause the animation when user scroll (for Mac user, drag the mouse or touchpad)
650
+ /// - Parameter runLoopMode: The runLoopMode for animation
651
+ public func runLoopMode( _ runLoopMode: RunLoop . Mode ) -> AnimatedImage {
652
+ var result = self
653
+ result. runLoopMode = runLoopMode
654
+ return result
655
+ }
656
+
657
+ /// Whether or not to pause the animation (keep current frame), instead of stop the animation (frame index reset to 0). When `isAnimating` binding value changed to false. Defaults is true.
658
+ /// - Note: For some of use case, you may want to reset the frame index to 0 when stop, but some other want to keep the current frame index.
659
+ /// - Parameter pausable: Whether or not to pause the animation instead of stop the animation.
660
+ public func pausable( _ pausable: Bool ) -> AnimatedImage {
661
+ var result = self
662
+ result. pausable = pausable
663
+ return result
664
+ }
665
+
666
+ /// Whether or not to clear frame buffer cache when stopped. Defaults is false.
667
+ /// Note: This is useful when you want to limit the memory usage during frequently visibility changes (such as image view inside a list view, then push and pop)
668
+ /// - Parameter purgeable: Whether or not to clear frame buffer cache when stopped.
669
+ public func purgeable( _ purgeable: Bool ) -> AnimatedImage {
670
+ var result = self
671
+ result. purgeable = purgeable
672
+ return result
673
+ }
674
+
675
+ /// Control the animation playback rate. Default is 1.0.
676
+ /// `1.0` means the normal speed.
677
+ /// `0.0` means stopping the animation.
678
+ /// `0.0-1.0` means the slow speed.
679
+ /// `> 1.0` means the fast speed.
680
+ /// `< 0.0` is not supported currently and stop animation. (may support reverse playback in the future)
681
+ /// - Parameter playBackRate: The animation playback rate.
682
+ public func playBackRate( _ playBackRate: Double ) -> AnimatedImage {
683
+ var result = self
684
+ result. playBackRate = playBackRate
685
+ return result
686
+ }
628
687
}
629
688
630
689
// Completion Handler
0 commit comments