Update the API of AnimatedImage as well
1. Change the placeholder into Web URL init method (placeholder not works for data/bundle init method) 2. Add convenient .progress/.activity syntax for AnimatedImage indicator
This commit is contained in:
parent
9ec9e29e14
commit
a94221fba0
|
@ -96,22 +96,19 @@ struct ContentView: View {
|
||||||
HStack {
|
HStack {
|
||||||
if self.animated {
|
if self.animated {
|
||||||
#if os(macOS) || os(iOS) || os(tvOS) || os(visionOS)
|
#if os(macOS) || os(iOS) || os(tvOS) || os(visionOS)
|
||||||
AnimatedImage(url: URL(string:url), isAnimating: .constant(true))
|
AnimatedImage(url: URL(string:url))
|
||||||
.onViewUpdate { view, context in
|
.onViewUpdate { view, context in
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
view.toolTip = url
|
view.toolTip = url
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.indicator(SDWebImageActivityIndicator.medium)
|
.indicator(.activity)
|
||||||
/**
|
|
||||||
.placeholder(UIImage(systemName: "photo"))
|
|
||||||
*/
|
|
||||||
.transition(.fade)
|
.transition(.fade)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: CGFloat(100), height: CGFloat(100), alignment: .center)
|
.frame(width: CGFloat(100), height: CGFloat(100), alignment: .center)
|
||||||
#else
|
#else
|
||||||
WebImage(url: URL(string:url), isAnimating: self.$animated)
|
WebImage(url: URL(string:url))
|
||||||
.resizable()
|
.resizable()
|
||||||
.indicator(.activity)
|
.indicator(.activity)
|
||||||
.transition(.fade(duration: 0.5))
|
.transition(.fade(duration: 0.5))
|
||||||
|
@ -119,13 +116,8 @@ struct ContentView: View {
|
||||||
.frame(width: CGFloat(100), height: CGFloat(100), alignment: .center)
|
.frame(width: CGFloat(100), height: CGFloat(100), alignment: .center)
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
WebImage(url: URL(string:url), isAnimating: .constant(true))
|
WebImage(url: URL(string:url))
|
||||||
.resizable()
|
.resizable()
|
||||||
/**
|
|
||||||
.placeholder {
|
|
||||||
Image(systemName: "photo")
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
.indicator(.activity)
|
.indicator(.activity)
|
||||||
.transition(.fade(duration: 0.5))
|
.transition(.fade(duration: 0.5))
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
|
|
|
@ -95,10 +95,9 @@ struct DetailView: View {
|
||||||
HStack {
|
HStack {
|
||||||
if animated {
|
if animated {
|
||||||
#if os(macOS) || os(iOS) || os(tvOS) || os(visionOS)
|
#if os(macOS) || os(iOS) || os(tvOS) || os(visionOS)
|
||||||
AnimatedImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder], isAnimating: $isAnimating)
|
AnimatedImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder], isAnimating: $isAnimating, placeholderImage: .wifiExclamationmark)
|
||||||
|
.indicator(.progress)
|
||||||
.resizable()
|
.resizable()
|
||||||
.placeholder(.wifiExclamationmark)
|
|
||||||
.indicator(SDWebImageProgressIndicator.default)
|
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
#else
|
#else
|
||||||
WebImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder], isAnimating: $isAnimating) { image in
|
WebImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder], isAnimating: $isAnimating) { image in
|
||||||
|
|
26
README.md
26
README.md
|
@ -128,18 +128,16 @@ github "SDWebImage/SDWebImageSwiftUI"
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var body: some View {
|
var body: some View {
|
||||||
WebImage(url: URL(string: "https://nokiatech.github.io/heif/content/images/ski_jump_1440x960.heic"))
|
WebImage(url: URL(string: "https://nokiatech.github.io/heif/content/images/ski_jump_1440x960.heic")) { image in
|
||||||
|
image.resizable() // Control layout like SwiftUI.AsyncImage, you must use this modifier or the view will use the image bitmap size
|
||||||
|
} placeholder: {
|
||||||
|
Rectangle().foregroundColor(.gray)
|
||||||
|
}
|
||||||
// Supports options and context, like `.delayPlaceholder` to show placeholder only when error
|
// Supports options and context, like `.delayPlaceholder` to show placeholder only when error
|
||||||
.onSuccess { image, data, cacheType in
|
.onSuccess { image, data, cacheType in
|
||||||
// Success
|
// Success
|
||||||
// Note: Data exist only when queried from disk cache or network. Use `.queryMemoryData` if you really need data
|
// 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
|
|
||||||
// Supports ViewBuilder as well
|
|
||||||
.placeholder {
|
|
||||||
Rectangle().foregroundColor(.gray)
|
|
||||||
}
|
|
||||||
.indicator(.activity) // Activity Indicator
|
.indicator(.activity) // Activity Indicator
|
||||||
.transition(.fade(duration: 0.5)) // Fade Transition with duration
|
.transition(.fade(duration: 0.5)) // Fade Transition with duration
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
|
@ -194,21 +192,21 @@ WebImage(url: url)
|
||||||
```swift
|
```swift
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"))
|
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"), placeholderImage: .init(systemName: "photo")) // Placeholder Image
|
||||||
// Supports options and context, like `.progressiveLoad` for progressive animation loading
|
// Supports options and context, like `.progressiveLoad` for progressive animation loading
|
||||||
.onFailure { error in
|
.onFailure { error in
|
||||||
// Error
|
// Error
|
||||||
}
|
}
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
.placeholder(UIImage(systemName: "photo")) // Placeholder Image
|
.indicator(.activity) // Activity Indicator
|
||||||
// Supports ViewBuilder as well
|
|
||||||
.placeholder {
|
|
||||||
Circle().foregroundColor(.gray)
|
|
||||||
}
|
|
||||||
.indicator(SDWebImageActivityIndicator.medium) // Activity Indicator
|
|
||||||
.transition(.fade) // Fade Transition
|
.transition(.fade) // Fade Transition
|
||||||
.scaledToFit() // Attention to call it on AnimatedImage, but not `some View` after View Modifier (Swift Protocol Extension method is static dispatched)
|
.scaledToFit() // Attention to call it on AnimatedImage, but not `some View` after View Modifier (Swift Protocol Extension method is static dispatched)
|
||||||
|
|
||||||
|
// Supports SwiftUI ViewBuilder placeholder as well
|
||||||
|
AnimatedImage(url: url) {
|
||||||
|
Circle().foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp")))
|
AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp")))
|
||||||
.customLoopCount(1) // Custom loop count
|
.customLoopCount(1) // Custom loop count
|
||||||
|
|
|
@ -31,6 +31,12 @@ final class AnimatedImageModel : ObservableObject {
|
||||||
@Published var url: URL?
|
@Published var url: URL?
|
||||||
@Published var webOptions: SDWebImageOptions = []
|
@Published var webOptions: SDWebImageOptions = []
|
||||||
@Published var webContext: [SDWebImageContextOption : Any]? = nil
|
@Published var webContext: [SDWebImageContextOption : Any]? = nil
|
||||||
|
@Published var placeholderImage: PlatformImage?
|
||||||
|
@Published var placeholderView: PlatformView? {
|
||||||
|
didSet {
|
||||||
|
oldValue?.removeFromSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Name image
|
/// Name image
|
||||||
@Published var name: String?
|
@Published var name: String?
|
||||||
@Published var bundle: Bundle?
|
@Published var bundle: Bundle?
|
||||||
|
@ -90,12 +96,6 @@ final class AnimatedImageConfiguration: ObservableObject {
|
||||||
// These configurations only useful for web image loading
|
// These configurations only useful for web image loading
|
||||||
var indicator: SDWebImageIndicator?
|
var indicator: SDWebImageIndicator?
|
||||||
var transition: SDWebImageTransition?
|
var transition: SDWebImageTransition?
|
||||||
var placeholder: PlatformImage?
|
|
||||||
var placeholderView: PlatformView? {
|
|
||||||
didSet {
|
|
||||||
oldValue?.removeFromSuperview()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Image View type to load image from url, data or bundle. Supports animated and static image format.
|
/// A Image View type to load image from url, data or bundle. Supports animated and static image format.
|
||||||
|
@ -115,13 +115,19 @@ public struct AnimatedImage : PlatformViewRepresentable {
|
||||||
/// True to start animation, false to stop animation.
|
/// True to start animation, false to stop animation.
|
||||||
@Binding public var isAnimating: Bool
|
@Binding public var isAnimating: Bool
|
||||||
|
|
||||||
/// Create an animated image with url, placeholder, custom options and context.
|
/// Create an animated image with url, placeholder, custom options and context, including animation control binding.
|
||||||
/// - Parameter url: The image url
|
/// - Parameter url: The image url
|
||||||
/// - Parameter placeholder: The placeholder image to show during loading
|
/// - Parameter placeholder: The placeholder image to show during loading
|
||||||
/// - Parameter options: The options to use when downloading the image. See `SDWebImageOptions` for the possible values.
|
/// - 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.
|
/// - 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) {
|
/// - Parameter isAnimating: The binding for animation control
|
||||||
self.init(url: url, options: options, context: context, isAnimating: .constant(true))
|
public init(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil, isAnimating: Binding<Bool> = .constant(true), placeholderImage: PlatformImage? = nil) {
|
||||||
|
let imageModel = AnimatedImageModel()
|
||||||
|
imageModel.url = url
|
||||||
|
imageModel.webOptions = options
|
||||||
|
imageModel.webContext = context
|
||||||
|
imageModel.placeholderImage = placeholderImage
|
||||||
|
self.init(imageModel: imageModel, isAnimating: isAnimating)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an animated image with url, placeholder, custom options and context, including animation control binding.
|
/// Create an animated image with url, placeholder, custom options and context, including animation control binding.
|
||||||
|
@ -130,46 +136,37 @@ public struct AnimatedImage : PlatformViewRepresentable {
|
||||||
/// - Parameter options: The options to use when downloading the image. See `SDWebImageOptions` for the possible values.
|
/// - 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.
|
/// - 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.
|
||||||
/// - Parameter isAnimating: The binding for animation control
|
/// - Parameter isAnimating: The binding for animation control
|
||||||
public init(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil, isAnimating: Binding<Bool>) {
|
public init<T>(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil, isAnimating: Binding<Bool> = .constant(true), @ViewBuilder placeholder: @escaping () -> T) where T : View {
|
||||||
let imageModel = AnimatedImageModel()
|
let imageModel = AnimatedImageModel()
|
||||||
imageModel.url = url
|
imageModel.url = url
|
||||||
imageModel.webOptions = options
|
imageModel.webOptions = options
|
||||||
imageModel.webContext = context
|
imageModel.webContext = context
|
||||||
|
#if os(macOS)
|
||||||
|
let hostingView = NSHostingView(rootView: placeholder())
|
||||||
|
#else
|
||||||
|
let hostingView = _UIHostingView(rootView: placeholder())
|
||||||
|
#endif
|
||||||
|
imageModel.placeholderView = hostingView
|
||||||
self.init(imageModel: imageModel, isAnimating: isAnimating)
|
self.init(imageModel: imageModel, isAnimating: isAnimating)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an animated image with name and bundle.
|
|
||||||
/// - Note: Asset Catalog is not supported.
|
|
||||||
/// - Parameter name: The image name
|
|
||||||
/// - Parameter bundle: The bundle contains image
|
|
||||||
public init(name: String, bundle: Bundle? = nil) {
|
|
||||||
self.init(name: name, bundle: bundle, isAnimating: .constant(true))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an animated image with name and bundle, including animation control binding.
|
/// Create an animated image with name and bundle, including animation control binding.
|
||||||
/// - Note: Asset Catalog is not supported.
|
/// - Note: Asset Catalog is not supported.
|
||||||
/// - Parameter name: The image name
|
/// - Parameter name: The image name
|
||||||
/// - Parameter bundle: The bundle contains image
|
/// - Parameter bundle: The bundle contains image
|
||||||
/// - Parameter isAnimating: The binding for animation control
|
/// - Parameter isAnimating: The binding for animation control
|
||||||
public init(name: String, bundle: Bundle? = nil, isAnimating: Binding<Bool>) {
|
public init(name: String, bundle: Bundle? = nil, isAnimating: Binding<Bool> = .constant(true)) {
|
||||||
let imageModel = AnimatedImageModel()
|
let imageModel = AnimatedImageModel()
|
||||||
imageModel.name = name
|
imageModel.name = name
|
||||||
imageModel.bundle = bundle
|
imageModel.bundle = bundle
|
||||||
self.init(imageModel: imageModel, isAnimating: isAnimating)
|
self.init(imageModel: imageModel, isAnimating: isAnimating)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an animated image with data and scale.
|
|
||||||
/// - Parameter data: The image data
|
|
||||||
/// - Parameter scale: The scale factor
|
|
||||||
public init(data: Data, scale: CGFloat = 1) {
|
|
||||||
self.init(data: data, scale: scale, isAnimating: .constant(true))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an animated image with data and scale, including animation control binding.
|
/// Create an animated image with data and scale, including animation control binding.
|
||||||
/// - Parameter data: The image data
|
/// - Parameter data: The image data
|
||||||
/// - Parameter scale: The scale factor
|
/// - Parameter scale: The scale factor
|
||||||
/// - Parameter isAnimating: The binding for animation control
|
/// - Parameter isAnimating: The binding for animation control
|
||||||
public init(data: Data, scale: CGFloat = 1, isAnimating: Binding<Bool>) {
|
public init(data: Data, scale: CGFloat = 1, isAnimating: Binding<Bool> = .constant(true)) {
|
||||||
let imageModel = AnimatedImageModel()
|
let imageModel = AnimatedImageModel()
|
||||||
imageModel.data = data
|
imageModel.data = data
|
||||||
imageModel.scale = scale
|
imageModel.scale = scale
|
||||||
|
@ -222,7 +219,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
|
||||||
func setupIndicator(_ view: AnimatedImageViewWrapper, context: Context) {
|
func setupIndicator(_ view: AnimatedImageViewWrapper, context: Context) {
|
||||||
view.wrapped.sd_imageIndicator = imageConfiguration.indicator
|
view.wrapped.sd_imageIndicator = imageConfiguration.indicator
|
||||||
view.wrapped.sd_imageTransition = imageConfiguration.transition
|
view.wrapped.sd_imageTransition = imageConfiguration.transition
|
||||||
if let placeholderView = imageConfiguration.placeholderView {
|
if let placeholderView = imageModel.placeholderView {
|
||||||
placeholderView.removeFromSuperview()
|
placeholderView.removeFromSuperview()
|
||||||
placeholderView.isHidden = true
|
placeholderView.isHidden = true
|
||||||
// Placeholder View should below the Indicator View
|
// Placeholder View should below the Indicator View
|
||||||
|
@ -243,13 +240,13 @@ public struct AnimatedImage : PlatformViewRepresentable {
|
||||||
context.coordinator.imageLoading.isLoading = true
|
context.coordinator.imageLoading.isLoading = true
|
||||||
let webOptions = imageModel.webOptions
|
let webOptions = imageModel.webOptions
|
||||||
if webOptions.contains(.delayPlaceholder) {
|
if webOptions.contains(.delayPlaceholder) {
|
||||||
self.imageConfiguration.placeholderView?.isHidden = true
|
self.imageModel.placeholderView?.isHidden = true
|
||||||
} else {
|
} else {
|
||||||
self.imageConfiguration.placeholderView?.isHidden = false
|
self.imageModel.placeholderView?.isHidden = false
|
||||||
}
|
}
|
||||||
var webContext = imageModel.webContext ?? [:]
|
var webContext = imageModel.webContext ?? [:]
|
||||||
webContext[.animatedImageClass] = SDAnimatedImage.self
|
webContext[.animatedImageClass] = SDAnimatedImage.self
|
||||||
view.wrapped.sd_internalSetImage(with: imageModel.url, placeholderImage: imageConfiguration.placeholder, options: webOptions, context: webContext, setImageBlock: nil, progress: { (receivedSize, expectedSize, _) in
|
view.wrapped.sd_internalSetImage(with: imageModel.url, placeholderImage: imageModel.placeholderImage, options: webOptions, context: webContext, setImageBlock: nil, progress: { (receivedSize, expectedSize, _) in
|
||||||
let progress: Double
|
let progress: Double
|
||||||
if (expectedSize > 0) {
|
if (expectedSize > 0) {
|
||||||
progress = Double(receivedSize) / Double(expectedSize)
|
progress = Double(receivedSize) / Double(expectedSize)
|
||||||
|
@ -265,10 +262,10 @@ public struct AnimatedImage : PlatformViewRepresentable {
|
||||||
context.coordinator.imageLoading.isLoading = false
|
context.coordinator.imageLoading.isLoading = false
|
||||||
context.coordinator.imageLoading.progress = 1
|
context.coordinator.imageLoading.progress = 1
|
||||||
if let image = image {
|
if let image = image {
|
||||||
self.imageConfiguration.placeholderView?.isHidden = true
|
self.imageModel.placeholderView?.isHidden = true
|
||||||
self.imageHandler.successBlock?(image, data, cacheType)
|
self.imageHandler.successBlock?(image, data, cacheType)
|
||||||
} else {
|
} else {
|
||||||
self.imageConfiguration.placeholderView?.isHidden = false
|
self.imageModel.placeholderView?.isHidden = false
|
||||||
self.imageHandler.failureBlock?(error ?? NSError())
|
self.imageHandler.failureBlock?(error ?? NSError())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -780,30 +777,19 @@ extension AnimatedImage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convenient indicator dot syntax
|
||||||
|
extension SDWebImageIndicator where Self == SDWebImageActivityIndicator {
|
||||||
|
public static var activity: Self { Self() }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SDWebImageIndicator where Self == SDWebImageProgressIndicator {
|
||||||
|
public static var progress: Self { Self() }
|
||||||
|
}
|
||||||
|
|
||||||
// Web Image convenience, based on UIKit/AppKit API
|
// Web Image convenience, based on UIKit/AppKit API
|
||||||
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||||
extension AnimatedImage {
|
extension AnimatedImage {
|
||||||
|
|
||||||
/// Associate a placeholder when loading image with url
|
|
||||||
/// - Parameter content: A view that describes the placeholder.
|
|
||||||
/// - note: The differences between this and placeholder image, it's that placeholder image replace the image for image view, but this modify the View Hierarchy to overlay the placeholder hosting view
|
|
||||||
public func placeholder<T>(@ViewBuilder content: () -> T) -> AnimatedImage where T : View {
|
|
||||||
#if os(macOS)
|
|
||||||
let hostingView = NSHostingView(rootView: content())
|
|
||||||
#else
|
|
||||||
let hostingView = _UIHostingView(rootView: content())
|
|
||||||
#endif
|
|
||||||
self.imageConfiguration.placeholderView = hostingView
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Associate a placeholder image when loading image with url
|
|
||||||
/// - Parameter content: A view that describes the placeholder.
|
|
||||||
public func placeholder(_ image: PlatformImage?) -> AnimatedImage {
|
|
||||||
self.imageConfiguration.placeholder = image
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Associate a indicator when loading image with url
|
/// Associate a indicator when loading image with url
|
||||||
/// - Note: If you do not need indicator, specify nil. Defaults to nil
|
/// - Note: If you do not need indicator, specify nil. Defaults to nil
|
||||||
/// - Parameter indicator: indicator, see more in `SDWebImageIndicator`
|
/// - Parameter indicator: indicator, see more in `SDWebImageIndicator`
|
||||||
|
@ -821,23 +807,6 @@ extension AnimatedImage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicator
|
|
||||||
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
|
||||||
extension AnimatedImage {
|
|
||||||
|
|
||||||
/// Associate a indicator when loading image with url
|
|
||||||
/// - Parameter indicator: The indicator type, see `Indicator`
|
|
||||||
public func indicator<T>(_ indicator: Indicator<T>) -> some View where T : View {
|
|
||||||
return self.modifier(IndicatorViewModifier(status: indicatorStatus, indicator: indicator))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Associate a indicator when loading image with url, convenient method with block
|
|
||||||
/// - Parameter content: A view that describes the indicator.
|
|
||||||
public func indicator<T>(@ViewBuilder content: @escaping (_ isAnimating: Binding<Bool>, _ progress: Binding<Double>) -> T) -> some View where T : View {
|
|
||||||
return indicator(Indicator(content: content))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||||
struct AnimatedImage_Previews : PreviewProvider {
|
struct AnimatedImage_Previews : PreviewProvider {
|
||||||
|
|
|
@ -142,7 +142,9 @@ class AnimatedImageTests: XCTestCase {
|
||||||
func testAnimatedImageModifier() throws {
|
func testAnimatedImageModifier() throws {
|
||||||
let expectation = self.expectation(description: "WebImage modifier")
|
let expectation = self.expectation(description: "WebImage modifier")
|
||||||
let imageUrl = URL(string: "https://assets.sbnation.com/assets/2512203/dogflops.gif")
|
let imageUrl = URL(string: "https://assets.sbnation.com/assets/2512203/dogflops.gif")
|
||||||
let imageView = AnimatedImage(url: imageUrl, options: [.progressiveLoad], context: [.imageScaleFactor: 1])
|
let imageView = AnimatedImage(url: imageUrl, options: [.progressiveLoad], context: [.imageScaleFactor: 1]) {
|
||||||
|
Circle()
|
||||||
|
}
|
||||||
let introspectView = imageView
|
let introspectView = imageView
|
||||||
.onSuccess { _, _, _ in
|
.onSuccess { _, _, _ in
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
|
@ -161,11 +163,7 @@ class AnimatedImageTests: XCTestCase {
|
||||||
XCTAssert(view.isKind(of: SDAnimatedImageView.self))
|
XCTAssert(view.isKind(of: SDAnimatedImageView.self))
|
||||||
XCTAssertEqual(context.coordinator.userInfo?["foo"] as? String, "bar")
|
XCTAssertEqual(context.coordinator.userInfo?["foo"] as? String, "bar")
|
||||||
}
|
}
|
||||||
.placeholder(PlatformImage())
|
.indicator(.activity)
|
||||||
.placeholder {
|
|
||||||
Circle()
|
|
||||||
}
|
|
||||||
.indicator(SDWebImageActivityIndicator.medium)
|
|
||||||
// Image
|
// Image
|
||||||
.resizable()
|
.resizable()
|
||||||
.renderingMode(.original)
|
.renderingMode(.original)
|
||||||
|
|
|
@ -73,7 +73,11 @@ class WebImageTests: XCTestCase {
|
||||||
func testWebImageModifier() throws {
|
func testWebImageModifier() throws {
|
||||||
let expectation = self.expectation(description: "WebImage modifier")
|
let expectation = self.expectation(description: "WebImage modifier")
|
||||||
let imageUrl = URL(string: "https://raw.githubusercontent.com/ibireme/YYImage/master/Demo/YYImageDemo/mew_baseline.jpg")
|
let imageUrl = URL(string: "https://raw.githubusercontent.com/ibireme/YYImage/master/Demo/YYImageDemo/mew_baseline.jpg")
|
||||||
let imageView = WebImage(url: imageUrl, options: [.progressiveLoad], context: [.imageScaleFactor: 1])
|
let imageView = WebImage(url: imageUrl, options: [.progressiveLoad], context: [.imageScaleFactor: 1]) { image in
|
||||||
|
image.resizable()
|
||||||
|
} placeholder: {
|
||||||
|
Circle()
|
||||||
|
}
|
||||||
let introspectView = imageView
|
let introspectView = imageView
|
||||||
.onSuccess { _, _, _ in
|
.onSuccess { _, _, _ in
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
|
@ -83,10 +87,6 @@ class WebImageTests: XCTestCase {
|
||||||
}
|
}
|
||||||
.onProgress { _, _ in
|
.onProgress { _, _ in
|
||||||
|
|
||||||
}
|
|
||||||
.placeholder(.init(platformImage: PlatformImage()))
|
|
||||||
.placeholder {
|
|
||||||
Circle()
|
|
||||||
}
|
}
|
||||||
// Image
|
// Image
|
||||||
.resizable()
|
.resizable()
|
||||||
|
|
Loading…
Reference in New Issue