From 0b646a62864144d8073092785986dad78f3d3dee Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 23 Feb 2021 15:59:44 +0800 Subject: [PATCH] Update with the playbackMode support for `WebImage` and `AnimatedImage` --- README.md | 1 + SDWebImageSwiftUI/Classes/AnimatedImage.swift | 26 +++++++++++-------- SDWebImageSwiftUI/Classes/ImagePlayer.swift | 6 ++++- .../Classes/ImageViewWrapper.swift | 14 ++++++++++ SDWebImageSwiftUI/Classes/WebImage.swift | 7 +++++ 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index abbf17a..08ca03d 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ var body: some View { // The initial value of binding should be true .customLoopCount(1) // Custom loop count .playbackRate(2.0) // Playback speed rate + .playbackMode(.bounce) // Playback normally to the end, then reversely back to the start // `WebImage` supports advanced control just like `AnimatedImage`, but without the progressive animation support } ``` diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index f442f6e..4f9c4e9 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -84,6 +84,7 @@ final class AnimatedImageConfiguration: ObservableObject { var pausable: Bool? var purgeable: Bool? var playbackRate: Double? + var playbackMode: SDAnimatedImagePlaybackMode? // These configurations only useful for web image loading var indicator: SDWebImageIndicator? var transition: SDWebImageTransition? @@ -253,7 +254,7 @@ public struct AnimatedImage : PlatformViewRepresentable { } else { // This is a hack because of iOS 13's SwiftUI bug, the @Published does not trigger another `updateUIView` call // Here I have to use UIKit/AppKit API to triger the same effect (the window change implicitly cause re-render) - if let hostingView = AnimatedImage.findHostingView(from: view) { + if let hostingView = view.findHostingView() { if let _ = hostingView.window { #if os(macOS) hostingView.viewDidMoveToWindow() @@ -542,17 +543,13 @@ public struct AnimatedImage : PlatformViewRepresentable { } else { view.wrapped.playbackRate = 1.0 } - } - - private static func findHostingView(from entry: PlatformView) -> PlatformView? { - var superview = entry.superview - while let s = superview { - if NSStringFromClass(type(of: s)).contains("HostingView") { - return s - } - superview = s.superview + + // Playback Mode + if let playbackMode = imageConfiguration.playbackMode { + view.wrapped.playbackMode = playbackMode + } else { + view.wrapped.playbackMode = .normal } - return nil } } @@ -717,6 +714,13 @@ extension AnimatedImage { self.imageConfiguration.playbackRate = playbackRate return self } + + /// Control the animation playback mode. Default is .normal + /// - Parameter playbackMode: The playback mode, including normal order, reverse order, bounce order and reversed bounce order. + public func playbackMode(_ playbackMode: SDAnimatedImagePlaybackMode) -> AnimatedImage { + self.imageConfiguration.playbackMode = playbackMode + return self + } } // Completion Handler diff --git a/SDWebImageSwiftUI/Classes/ImagePlayer.swift b/SDWebImageSwiftUI/Classes/ImagePlayer.swift index 0b9cd02..b8af86c 100644 --- a/SDWebImageSwiftUI/Classes/ImagePlayer.swift +++ b/SDWebImageSwiftUI/Classes/ImagePlayer.swift @@ -26,6 +26,9 @@ public final class ImagePlayer : ObservableObject { /// Animation playback rate public var playbackRate: Double = 1.0 + /// Animation playback mode + public var playbackMode: SDAnimatedImagePlaybackMode = .normal + deinit { player?.stopPlaying() currentFrame = nil @@ -71,10 +74,11 @@ public final class ImagePlayer : ObservableObject { imagePlayer.maxBufferSize = maxBufferSize } if let customLoopCount = customLoopCount { - imagePlayer.totalLoopCount = UInt(customLoopCount) + imagePlayer.totalLoopCount = customLoopCount } imagePlayer.runLoopMode = runLoopMode imagePlayer.playbackRate = playbackRate + imagePlayer.playbackMode = playbackMode self.player = imagePlayer diff --git a/SDWebImageSwiftUI/Classes/ImageViewWrapper.swift b/SDWebImageSwiftUI/Classes/ImageViewWrapper.swift index 6946ee6..80f936e 100644 --- a/SDWebImageSwiftUI/Classes/ImageViewWrapper.swift +++ b/SDWebImageSwiftUI/Classes/ImageViewWrapper.swift @@ -114,6 +114,20 @@ extension PlatformView { self.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: 0).isActive = true self.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: 0).isActive = true } + + /// Finding the HostingView for UIKit/AppKit View. + /// - Parameter entry: The entry platform view + /// - Returns: The hosting view. + func findHostingView() -> PlatformView? { + var superview = self.superview + while let s = superview { + if NSStringFromClass(type(of: s)).contains("HostingView") { + return s + } + superview = s.superview + } + return nil + } } #endif diff --git a/SDWebImageSwiftUI/Classes/WebImage.swift b/SDWebImageSwiftUI/Classes/WebImage.swift index 5f04d1d..e435335 100644 --- a/SDWebImageSwiftUI/Classes/WebImage.swift +++ b/SDWebImageSwiftUI/Classes/WebImage.swift @@ -399,6 +399,13 @@ extension WebImage { self.imagePlayer.playbackRate = playbackRate return self } + + /// Control the animation playback mode. Default is .normal + /// - Parameter playbackMode: The playback mode, including normal order, reverse order, bounce order and reversed bounce order. + public func playbackMode(_ playbackMode: SDAnimatedImagePlaybackMode) -> WebImage { + self.imagePlayer.playbackMode = playbackMode + return self + } } #if DEBUG