Skip to content

Commit af644e4

Browse files
authored
Merge pull request #168 from SDWebImage/feature_playbackmode
Update with the playbackMode support for `WebImage` and `AnimatedImage`
2 parents a30a71a + 0b646a6 commit af644e4

File tree

5 files changed

+42
-12
lines changed

5 files changed

+42
-12
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ var body: some View {
160160
// The initial value of binding should be true
161161
.customLoopCount(1) // Custom loop count
162162
.playbackRate(2.0) // Playback speed rate
163+
.playbackMode(.bounce) // Playback normally to the end, then reversely back to the start
163164
// `WebImage` supports advanced control just like `AnimatedImage`, but without the progressive animation support
164165
}
165166
```

SDWebImageSwiftUI/Classes/AnimatedImage.swift

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ final class AnimatedImageConfiguration: ObservableObject {
8484
var pausable: Bool?
8585
var purgeable: Bool?
8686
var playbackRate: Double?
87+
var playbackMode: SDAnimatedImagePlaybackMode?
8788
// These configurations only useful for web image loading
8889
var indicator: SDWebImageIndicator?
8990
var transition: SDWebImageTransition?
@@ -253,7 +254,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
253254
} else {
254255
// This is a hack because of iOS 13's SwiftUI bug, the @Published does not trigger another `updateUIView` call
255256
// Here I have to use UIKit/AppKit API to triger the same effect (the window change implicitly cause re-render)
256-
if let hostingView = AnimatedImage.findHostingView(from: view) {
257+
if let hostingView = view.findHostingView() {
257258
if let _ = hostingView.window {
258259
#if os(macOS)
259260
hostingView.viewDidMoveToWindow()
@@ -542,17 +543,13 @@ public struct AnimatedImage : PlatformViewRepresentable {
542543
} else {
543544
view.wrapped.playbackRate = 1.0
544545
}
545-
}
546-
547-
private static func findHostingView(from entry: PlatformView) -> PlatformView? {
548-
var superview = entry.superview
549-
while let s = superview {
550-
if NSStringFromClass(type(of: s)).contains("HostingView") {
551-
return s
552-
}
553-
superview = s.superview
546+
547+
// Playback Mode
548+
if let playbackMode = imageConfiguration.playbackMode {
549+
view.wrapped.playbackMode = playbackMode
550+
} else {
551+
view.wrapped.playbackMode = .normal
554552
}
555-
return nil
556553
}
557554
}
558555

@@ -717,6 +714,13 @@ extension AnimatedImage {
717714
self.imageConfiguration.playbackRate = playbackRate
718715
return self
719716
}
717+
718+
/// Control the animation playback mode. Default is .normal
719+
/// - Parameter playbackMode: The playback mode, including normal order, reverse order, bounce order and reversed bounce order.
720+
public func playbackMode(_ playbackMode: SDAnimatedImagePlaybackMode) -> AnimatedImage {
721+
self.imageConfiguration.playbackMode = playbackMode
722+
return self
723+
}
720724
}
721725

722726
// Completion Handler

SDWebImageSwiftUI/Classes/ImagePlayer.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ public final class ImagePlayer : ObservableObject {
2626
/// Animation playback rate
2727
public var playbackRate: Double = 1.0
2828

29+
/// Animation playback mode
30+
public var playbackMode: SDAnimatedImagePlaybackMode = .normal
31+
2932
deinit {
3033
player?.stopPlaying()
3134
currentFrame = nil
@@ -71,10 +74,11 @@ public final class ImagePlayer : ObservableObject {
7174
imagePlayer.maxBufferSize = maxBufferSize
7275
}
7376
if let customLoopCount = customLoopCount {
74-
imagePlayer.totalLoopCount = UInt(customLoopCount)
77+
imagePlayer.totalLoopCount = customLoopCount
7578
}
7679
imagePlayer.runLoopMode = runLoopMode
7780
imagePlayer.playbackRate = playbackRate
81+
imagePlayer.playbackMode = playbackMode
7882

7983
self.player = imagePlayer
8084

SDWebImageSwiftUI/Classes/ImageViewWrapper.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,20 @@ extension PlatformView {
114114
self.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: 0).isActive = true
115115
self.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: 0).isActive = true
116116
}
117+
118+
/// Finding the HostingView for UIKit/AppKit View.
119+
/// - Parameter entry: The entry platform view
120+
/// - Returns: The hosting view.
121+
func findHostingView() -> PlatformView? {
122+
var superview = self.superview
123+
while let s = superview {
124+
if NSStringFromClass(type(of: s)).contains("HostingView") {
125+
return s
126+
}
127+
superview = s.superview
128+
}
129+
return nil
130+
}
117131
}
118132

119133
#endif

SDWebImageSwiftUI/Classes/WebImage.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,13 @@ extension WebImage {
399399
self.imagePlayer.playbackRate = playbackRate
400400
return self
401401
}
402+
403+
/// Control the animation playback mode. Default is .normal
404+
/// - Parameter playbackMode: The playback mode, including normal order, reverse order, bounce order and reversed bounce order.
405+
public func playbackMode(_ playbackMode: SDAnimatedImagePlaybackMode) -> WebImage {
406+
self.imagePlayer.playbackMode = playbackMode
407+
return self
408+
}
402409
}
403410

404411
#if DEBUG

0 commit comments

Comments
 (0)