Add the same overload method for onSuccess API, which introduce the image data arg. Keep the source code compatibility

This commit is contained in:
DreamPiggy 2020-05-06 23:06:39 +08:00
parent 8a347dc4dc
commit b174fee26b
4 changed files with 81 additions and 11 deletions

View File

@ -111,8 +111,9 @@ github "SDWebImage/SDWebImageSwiftUI"
var body: some View {
WebImage(url: URL(string: "https://nokiatech.github.io/heif/content/images/ski_jump_1440x960.heic"))
// Supports options and context, like `.delayPlaceholder` to show placeholder only when error
.onSuccess { image, cacheType in
.onSuccess { image, data, cacheType in
// Success
// Note: Data exist only when queried from disk cache or network. Use `.queryMemoryData` if you really need data
}
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
.placeholder(Image(systemName: "photo")) // Placeholder Image

View File

@ -49,7 +49,7 @@ final class AnimatedLoadingModel : ObservableObject, IndicatorReportable {
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
final class AnimatedImageHandler: ObservableObject {
// Completion Handler
@Published var successBlock: ((PlatformImage, SDImageCacheType) -> Void)?
@Published var successBlock: ((PlatformImage, Data?, SDImageCacheType) -> Void)?
@Published var failureBlock: ((Error) -> Void)?
@Published var progressBlock: ((Int, Int) -> Void)?
// Coordinator Handler
@ -208,12 +208,15 @@ public struct AnimatedImage : PlatformViewRepresentable {
return
}
self.imageLoading.isLoading = true
if imageModel.webOptions.contains(.delayPlaceholder) {
let options = imageModel.webOptions
if options.contains(.delayPlaceholder) {
self.imageConfiguration.placeholderView?.isHidden = true
} else {
self.imageConfiguration.placeholderView?.isHidden = false
}
view.wrapped.sd_setImage(with: imageModel.url, placeholderImage: imageConfiguration.placeholder, options: imageModel.webOptions, context: imageModel.webContext, progress: { (receivedSize, expectedSize, _) in
var context = imageModel.webContext ?? [:]
context[.animatedImageClass] = SDAnimatedImage.self
view.wrapped.sd_internalSetImage(with: imageModel.url, placeholderImage: imageConfiguration.placeholder, options: options, context: context, setImageBlock: nil, progress: { (receivedSize, expectedSize, _) in
let progress: Double
if (expectedSize > 0) {
progress = Double(receivedSize) / Double(expectedSize)
@ -224,7 +227,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
self.imageLoading.progress = progress
}
self.imageHandler.progressBlock?(receivedSize, expectedSize)
}) { (image, error, cacheType, _) in
}) { (image, data, error, cacheType, finished, _) in
// This is a hack because of Xcode 11.3 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) {
@ -241,7 +244,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
self.imageLoading.progress = 1
if let image = image {
self.imageConfiguration.placeholderView?.isHidden = true
self.imageHandler.successBlock?(image, cacheType)
self.imageHandler.successBlock?(image, data, cacheType)
} else {
self.imageConfiguration.placeholderView?.isHidden = false
self.imageHandler.failureBlock?(error ?? NSError())
@ -702,11 +705,33 @@ extension AnimatedImage {
return self
}
/// Provide the action when image load successes.
/// - Parameters:
/// - action: The action to perform. The first arg is the loaded image. If `action` is `nil`, the call has no effect.
/// - Returns: A view that triggers `action` when this image load successes.
public func onSuccess(perform action: @escaping (PlatformImage) -> Void) -> AnimatedImage {
self.imageHandler.successBlock = { image, _, _ in
action(image)
}
return self
}
/// Provide the action when image load successes.
/// - Parameters:
/// - action: The action to perform. The first arg is the loaded image, the second arg is the cache type loaded from. If `action` is `nil`, the call has no effect.
/// - Returns: A view that triggers `action` when this image load successes.
public func onSuccess(perform action: ((PlatformImage, SDImageCacheType) -> Void)? = nil) -> AnimatedImage {
public func onSuccess(perform action: @escaping (PlatformImage, SDImageCacheType) -> Void) -> AnimatedImage {
self.imageHandler.successBlock = { image, _, cacheType in
action(image, cacheType)
}
return self
}
/// Provide the action when image load successes.
/// - Parameters:
/// - action: The action to perform. The first arg is the loaded image, the second arg is the loaded image data, the third arg is the cache type loaded from. If `action` is `nil`, the call has no effect.
/// - Returns: A view that triggers `action` when this image load successes.
public func onSuccess(perform action: ((PlatformImage, Data?, SDImageCacheType) -> Void)? = nil) -> AnimatedImage {
self.imageHandler.successBlock = action
return self
}

View File

@ -17,6 +17,8 @@ public final class ImageManager : ObservableObject {
@Published public var image: PlatformImage?
/// loaded image data, may be nil if hit from memory cache. This will only published once even on incremental image loading
@Published public var imageData: Data?
/// loaded image cache type, .none means from network
@Published public var cacheType: SDImageCacheType = .none
/// loading error, you can grab the error code and reason listed in `SDWebImageErrorDomain`, to provide a user interface about the error reason
@Published public var error: Error?
/// whether network is loading or cache is querying, should only be used for indicator binding
@ -33,7 +35,7 @@ public final class ImageManager : ObservableObject {
var url: URL?
var options: SDWebImageOptions
var context: [SDWebImageContextOption : Any]?
var successBlock: ((PlatformImage, SDImageCacheType) -> Void)?
var successBlock: ((PlatformImage, Data?, SDImageCacheType) -> Void)?
var failureBlock: ((Error) -> Void)?
var progressBlock: ((Int, Int) -> Void)?
@ -89,10 +91,11 @@ public final class ImageManager : ObservableObject {
self.isIncremental = !finished
if finished {
self.imageData = data
self.cacheType = cacheType
self.isLoading = false
self.progress = 1
if let image = image {
self.successBlock?(image, cacheType)
self.successBlock?(image, data, cacheType)
} else {
self.failureBlock?(error ?? NSError())
}
@ -120,10 +123,28 @@ extension ImageManager {
self.failureBlock = action
}
/// Provide the action when image load successes.
/// - Parameters:
/// - action: The action to perform. The first arg is the loaded image. If `action` is `nil`, the call has no effect.
public func setOnSuccess(perform action: @escaping (PlatformImage) -> Void) {
self.successBlock = { image, _, _ in
action(image)
}
}
/// Provide the action when image load successes.
/// - Parameters:
/// - action: The action to perform. The first arg is the loaded image, the second arg is the cache type loaded from. If `action` is `nil`, the call has no effect.
public func setOnSuccess(perform action: ((PlatformImage, SDImageCacheType) -> Void)? = nil) {
public func setOnSuccess(perform action: @escaping (PlatformImage, SDImageCacheType) -> Void) {
self.successBlock = { image, _, cacheType in
action(image, cacheType)
}
}
/// Provide the action when image load successes.
/// - Parameters:
/// - action: The action to perform. The first arg is the loaded image, the second arg is the loaded image data, the third arg is the cache type loaded from. If `action` is `nil`, the call has no effect.
public func setOnSuccess(perform action: ((PlatformImage, Data?, SDImageCacheType) -> Void)? = nil) {
self.successBlock = action
}

View File

@ -264,11 +264,34 @@ extension WebImage {
return self
}
/// Provide the action when image load successes.
/// - Parameters:
/// - action: The action to perform. The first arg is the loaded image. If `action` is `nil`, the call has no effect.
/// - Returns: A view that triggers `action` when this image load successes.
public func onSuccess(perform action: @escaping (PlatformImage) -> Void) -> WebImage {
let action = action
self.imageManager.successBlock = { image, _, _ in
action(image)
}
return self
}
/// Provide the action when image load successes.
/// - Parameters:
/// - action: The action to perform. The first arg is the loaded image, the second arg is the cache type loaded from. If `action` is `nil`, the call has no effect.
/// - Returns: A view that triggers `action` when this image load successes.
public func onSuccess(perform action: ((PlatformImage, SDImageCacheType) -> Void)? = nil) -> WebImage {
public func onSuccess(perform action: @escaping (PlatformImage, SDImageCacheType) -> Void) -> WebImage {
self.imageManager.successBlock = { image, _, cacheType in
action(image, cacheType)
}
return self
}
/// Provide the action when image load successes.
/// - Parameters:
/// - action: The action to perform. The first arg is the loaded image, the second arg is the loaded image data, the third arg is the cache type loaded from. If `action` is `nil`, the call has no effect.
/// - Returns: A view that triggers `action` when this image load successes.
public func onSuccess(perform action: ((PlatformImage, Data?, SDImageCacheType) -> Void)? = nil) -> WebImage {
self.imageManager.successBlock = action
return self
}