Refactory the pure SwiftUI AnimatedImage implementation, right in the WebImage view.

Support watchOS as well :) Good SwiftUI
This commit is contained in:
DreamPiggy 2019-11-30 01:37:28 +08:00
parent 58434833b3
commit 33c11b1cf0
4 changed files with 91 additions and 12 deletions

View File

@ -38,7 +38,7 @@ struct ContentView: View {
"https://raw.githubusercontent.com/icons8/flat-color-icons/master/pdf/stack_of_photos.pdf",
"https://raw.githubusercontent.com/icons8/flat-color-icons/master/pdf/smartphone_tablet.pdf"
]
@State var animated: Bool = false // You can change between WebImage/AnimatedImage
@State var animated: Bool = true // You can change between WebImage/AnimatedImage
var body: some View {
#if os(iOS) || os(tvOS)
@ -105,8 +105,16 @@ struct ContentView: View {
.scaledToFit()
.frame(width: CGFloat(100), height: CGFloat(100), alignment: .center)
#else
AnimatedImage(url: URL(string:url))
WebImage(url: URL(string:url))
.resizable()
.animated()
.indicator { _, _ in
ActivityBar()
.foregroundColor(Color.white)
.frame(width: 50, height: 50)
}
.animation(.easeInOut(duration: 0.5))
.transition(.fade)
.scaledToFit()
.frame(width: CGFloat(100), height: CGFloat(100), alignment: .center)
#endif

View File

@ -95,8 +95,14 @@ struct DetailView: View {
.resizable()
.scaledToFit()
#else
AnimatedImage(url: URL(string:url), options: [.progressiveLoad], isAnimating: $isAnimating)
WebImage(url: URL(string:url), options: [.progressiveLoad])
.resizable()
.animated(isAnimating)
.indicator { isAnimating, progress in
ProgressBar(value: progress)
.foregroundColor(.blue)
.frame(maxHeight: 6)
}
.scaledToFit()
#endif
} else {

View File

@ -11,10 +11,6 @@ import SDWebImage
/// A Image View type to load image from url. Supports static image format.
public struct WebImage : View {
var url: URL?
var options: SDWebImageOptions
var context: [SDWebImageContextOption : Any]?
var configurations: [(Image) -> Image] = []
var placeholder: AnyView?
@ -23,14 +19,16 @@ public struct WebImage : View {
@ObservedObject var imageManager: ImageManager
// Animated Image support (Beta)
var animated: Bool = false
@State var currentFrame: PlatformImage? = nil
@State var imagePlayer: SDAnimatedImagePlayer? = nil
/// Create a web image with url, placeholder, custom options and context.
/// - Parameter url: The image url
/// - Parameter options: The options to use when downloading the image. See `SDWebImageOptions` for the possible values.
/// - 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.
public init(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil) {
self.url = url
self.options = options
self.context = context
self.imageManager = ImageManager(url: url, options: options, context: context)
// load remote image here, SwiftUI sometimes will create a new View struct without calling `onAppear` (like enter EditMode) :)
// this can ensure we load the image, SDWebImage take care of the duplicated query
@ -40,8 +38,29 @@ public struct WebImage : View {
public var body: some View {
Group {
if imageManager.image != nil {
configurations.reduce(Image(platformImage: imageManager.image!)) { (previous, configuration) in
configuration(previous)
if animated {
if currentFrame != nil {
configurations.reduce(Image(platformImage: currentFrame!)) { (previous, configuration) in
configuration(previous)
}
.onAppear {
self.imagePlayer?.startPlaying()
}
.onDisappear {
self.imagePlayer?.pausePlaying()
}
} else {
configurations.reduce(Image(platformImage: imageManager.image!)) { (previous, configuration) in
configuration(previous)
}
.onReceive(imageManager.$image) { image in
self.setupPlayer(image: image)
}
}
} else {
configurations.reduce(Image(platformImage: imageManager.image!)) { (previous, configuration) in
configuration(previous)
}
}
} else {
Group {
@ -194,6 +213,51 @@ extension WebImage {
}
}
// Animated Image support (Beta)
extension WebImage {
/// Make the image to support animated images. The animation will start when view appears, and pause when disappears.
/// - 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)
/// - Warning: This API need polishing. In the future we may choose to create a new View type instead.
///
/// - Parameter animated: Whether or not to enable animationn.
public func animated(_ animated: Bool = true) -> WebImage {
var result = self
result.animated = animated
if animated {
// Update Image Manager
result.imageManager.cancel()
var context = result.imageManager.context ?? [:]
context[.animatedImageClass] = SDAnimatedImage.self
result.imageManager.context = context
result.imageManager.load()
} else {
// Update Image Manager
result.imageManager.cancel()
var context = result.imageManager.context ?? [:]
context[.animatedImageClass] = nil
result.imageManager.context = context
result.imageManager.load()
}
return result
}
func setupPlayer(image: PlatformImage?) {
if imagePlayer != nil {
return
}
if let animatedImage = image as? SDAnimatedImageProvider {
if let imagePlayer = SDAnimatedImagePlayer(provider: animatedImage) {
imagePlayer.animationFrameHandler = { (_, frame) in
self.currentFrame = frame
}
self.imagePlayer = imagePlayer
imagePlayer.startPlaying()
}
}
}
}
#if DEBUG
struct WebImage_Previews : PreviewProvider {
static var previews: some View {

View File

@ -15,3 +15,4 @@ FOUNDATION_EXPORT double SDWebImageSwiftUIVersionNumber;
FOUNDATION_EXPORT const unsigned char SDWebImageSwiftUIVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <SDWebImageSwiftUI/PublicHeader.h>
#import <SDWebImage/SDWebImage.h>