Skip to content

Commit 9589a58

Browse files
authored
Merge pull request #46 from SDWebImage/feature_watchOS_player
Refactory the watchOS Animation solution using the SDAnimatedImagePlayer (~> 5.3.0)
2 parents 2a5b0ef + 0569474 commit 9589a58

File tree

9 files changed

+213
-198
lines changed

9 files changed

+213
-198
lines changed

Cartfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
github "SDWebImage/SDWebImage" ~> 5.1
1+
github "SDWebImage/SDWebImage" ~> 5.3

Cartfile.resolved

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
github "SDWebImage/SDWebImage" "5.2.3"
1+
github "SDWebImage/SDWebImage" "5.3.0"

Example/Podfile.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ PODS:
88
- libwebp/mux (1.0.3):
99
- libwebp/demux
1010
- libwebp/webp (1.0.3)
11-
- SDWebImage (5.2.5):
12-
- SDWebImage/Core (= 5.2.5)
13-
- SDWebImage/Core (5.2.5)
14-
- SDWebImageSwiftUI (0.6.2):
15-
- SDWebImage (~> 5.1)
11+
- SDWebImage (5.3.0):
12+
- SDWebImage/Core (= 5.3.0)
13+
- SDWebImage/Core (5.3.0)
14+
- SDWebImageSwiftUI (0.7.0):
15+
- SDWebImage (~> 5.3)
1616
- SDWebImageWebPCoder (0.2.5):
1717
- libwebp (~> 1.0)
1818
- SDWebImage/Core (~> 5.0)
@@ -33,8 +33,8 @@ EXTERNAL SOURCES:
3333

3434
SPEC CHECKSUMS:
3535
libwebp: 057912d6d0abfb6357d8bb05c0ea470301f5d61e
36-
SDWebImage: 4eabf2fa6695c95c47724214417a9c036c965e4a
37-
SDWebImageSwiftUI: 26a485e004cd64f5dde194bd97882aba962ab5b0
36+
SDWebImage: f1afa74b86587c2c63f4e80dfd39b21e3c17b45b
37+
SDWebImageSwiftUI: 72add2eb640bdadc856cdc30954528bffe8dfec0
3838
SDWebImageWebPCoder: 947093edd1349d820c40afbd9f42acb6cdecd987
3939

4040
PODFILE CHECKSUM: 3fb06a5173225e197f3a4bf2be7e5586a693257a

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ let package = Package(
1717
dependencies: [
1818
// Dependencies declare other packages that this package depends on.
1919
// .package(url: /* package url */, from: "1.0.0"),
20-
.package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.1.0")
20+
.package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.3.0")
2121
],
2222
targets: [
2323
// Targets are the basic building blocks of a package. A target can define a module or a test suite.

SDWebImageSwiftUI.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ Which aims to provide a better support for SwiftUI users.
2929
s.source_files = 'SDWebImageSwiftUI/Classes/**/*', 'SDWebImageSwiftUI/Module/*.h'
3030

3131
s.frameworks = 'SwiftUI'
32-
s.dependency 'SDWebImage', '~> 5.1'
32+
s.dependency 'SDWebImage', '~> 5.3'
3333
s.swift_version = '5.1'
3434
end

SDWebImageSwiftUI/Classes/AnimatedImage.swift

Lines changed: 88 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ import SDWebImage
1212
import SDWebImageSwiftUIObjC
1313
#endif
1414

15-
// Data Binding Object
16-
final class AnimatedImageModel : ObservableObject {
17-
@Published var image: PlatformImage?
18-
}
19-
2015
// Convenient
2116
#if os(watchOS)
2217
public typealias AnimatedImageViewWrapper = SDAnimatedImageInterface
@@ -39,10 +34,9 @@ public final class AnimatedImageCoordinator: NSObject {
3934

4035
// View
4136
public struct AnimatedImage : PlatformViewRepresentable {
42-
@ObservedObject var imageModel = AnimatedImageModel()
43-
4437
// Options
4538
var url: URL?
39+
@State var image: PlatformImage?
4640
var webOptions: SDWebImageOptions = []
4741
var webContext: [SDWebImageContextOption : Any]? = nil
4842

@@ -64,6 +58,10 @@ public struct AnimatedImage : PlatformViewRepresentable {
6458
var incrementalLoad: Bool?
6559
var maxBufferSize: UInt?
6660
var customLoopCount: Int?
61+
var runLoopMode: RunLoop.Mode?
62+
var pausable: Bool?
63+
var purgeable: Bool?
64+
var playBackRate: Double?
6765
#if os(macOS) || os(iOS) || os(tvOS)
6866
// These configurations only useful for web image loading
6967
var indicator: SDWebImageIndicator?
@@ -80,11 +78,6 @@ public struct AnimatedImage : PlatformViewRepresentable {
8078
/// True to start animation, false to stop animation.
8179
@Binding public var isAnimating: Bool
8280

83-
/// Current loaded image, may be `SDAnimatedImage` type
84-
public var image: PlatformImage? {
85-
imageModel.image
86-
}
87-
8881
/// Create an animated image with url, placeholder, custom options and context.
8982
/// - Parameter url: The image url
9083
/// - Parameter placeholder: The placeholder image to show during loading
@@ -127,7 +120,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
127120
#else
128121
let image = SDAnimatedImage(named: name, in: bundle, compatibleWith: nil)
129122
#endif
130-
self.imageModel.image = image
123+
self.image = image
131124
}
132125

133126
/// Create an animated image with data and scale.
@@ -144,7 +137,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
144137
public init(data: Data, scale: CGFloat = 0, isAnimating: Binding<Bool>) {
145138
self._isAnimating = isAnimating
146139
let image = SDAnimatedImage(data: data, scale: scale)
147-
self.imageModel.image = image
140+
self.image = image
148141
}
149142

150143
#if os(macOS)
@@ -208,8 +201,10 @@ public struct AnimatedImage : PlatformViewRepresentable {
208201
view.wrapped.sd_setImage(with: url, placeholderImage: placeholder, options: webOptions, context: webContext, progress: { (receivedSize, expectedSize, _) in
209202
self.progressBlock?(receivedSize, expectedSize)
210203
}) { (image, error, cacheType, _) in
204+
DispatchQueue.main.async {
205+
self.image = image
206+
}
211207
if let image = image {
212-
self.imageModel.image = image
213208
self.successBlock?(image, cacheType)
214209
} else {
215210
self.failureBlock?(error ?? NSError())
@@ -226,12 +221,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
226221
}
227222

228223
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 {
235225
#if os(watchOS)
236226
view.wrapped.setImage(image)
237227
#else
@@ -248,7 +238,9 @@ public struct AnimatedImage : PlatformViewRepresentable {
248238
}
249239

250240
#if os(macOS)
251-
view.wrapped.animates = self.isAnimating
241+
if self.isAnimating != view.wrapped.animates {
242+
view.wrapped.animates = self.isAnimating
243+
}
252244
#else
253245
if self.isAnimating != view.wrapped.isAnimating {
254246
if self.isAnimating {
@@ -338,17 +330,15 @@ public struct AnimatedImage : PlatformViewRepresentable {
338330

339331
#if os(macOS)
340332
view.wrapped.imageScaling = contentMode
341-
#elseif os(iOS) || os(tvOS)
333+
#else
342334
view.wrapped.contentMode = contentMode
343-
#elseif os(watchOS)
344-
view.wrapped.setContentMode(contentMode)
345335
#endif
346336

347337
// 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) {
349339
var image = image
350340
// ResizingMode
351-
if let resizingMode = self.resizingMode {
341+
if let resizingMode = self.resizingMode, capInsets != EdgeInsets() {
352342
#if os(macOS)
353343
let capInsets = NSEdgeInsets(top: self.capInsets.top, left: self.capInsets.leading, bottom: self.capInsets.bottom, right: self.capInsets.trailing)
354344
#else
@@ -467,12 +457,40 @@ public struct AnimatedImage : PlatformViewRepresentable {
467457
}
468458
#elseif os(watchOS)
469459
if let customLoopCount = self.customLoopCount {
470-
view.wrapped.setAnimationRepeatCount(customLoopCount as NSNumber)
460+
view.wrapped.animationRepeatCount = customLoopCount as NSNumber
471461
} else {
472462
// disable custom loop count
473-
view.wrapped.setAnimationRepeatCount(nil)
463+
view.wrapped.animationRepeatCount = nil
474464
}
475465
#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+
}
476494
}
477495
}
478496

@@ -625,6 +643,47 @@ extension AnimatedImage {
625643
result.incrementalLoad = incrementalLoad
626644
return result
627645
}
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+
}
628687
}
629688

630689
// Completion Handler

SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@ NS_ASSUME_NONNULL_BEGIN
1515
@interface SDAnimatedImageInterface : WKInterfaceImage
1616

1717
@property (nonatomic, assign, getter=isAnimating, readonly) BOOL animating;
18+
@property (nonatomic, assign) SDImageScaleMode contentMode;
19+
@property (nonatomic, strong, nullable) NSNumber *animationRepeatCount;
20+
@property (nonatomic, copy) NSRunLoopMode runLoopMode;
21+
@property (nonatomic, assign) BOOL resetFrameIndexWhenStopped;
22+
@property (nonatomic, assign) BOOL clearBufferWhenStopped;
23+
@property (nonatomic, assign) double playbackRate;
1824

1925
- (instancetype)init WK_AVAILABLE_WATCHOS_ONLY(6.0);
20-
- (void)setContentMode:(SDImageScaleMode)contentMode;
21-
- (void)setAnimationRepeatCount:(nullable NSNumber *)repeatCount;
26+
27+
/// Trigger the animation check when view appears/disappears
2228
- (void)updateAnimation;
2329

2430
@end

0 commit comments

Comments
 (0)