Merge pull request #91 from SDWebImage/feature_delayPlaceholder_webimage
Supports the `delayPlaceholder` for WebImage
This commit is contained in:
commit
42fdca6753
24
Example/SDWebImageSwiftUIDemo-macOS/Assets.xcassets/wifi.exclamationmark.imageset/Contents.json
vendored
Normal file
24
Example/SDWebImageSwiftUIDemo-macOS/Assets.xcassets/wifi.exclamationmark.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "wifi.exclamationmark.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="56" height="56" viewBox="0 0 56 56"><path d="M 28.0234 37.5039 C 29.2656 37.5039 30.1093 36.6836 30.1327 35.3945 C 30.2031 26.7695 30.2734 18.0976 30.3437 9.4492 C 30.3437 8.1133 29.2656 7.1992 27.9999 7.1992 C 26.7343 7.1992 25.6562 8.1133 25.6562 9.4492 C 25.7499 18.0976 25.8203 26.7695 25.9140 35.3945 C 25.9374 36.6836 26.7812 37.5039 28.0234 37.5039 Z M 5.4531 26.3711 C 5.8984 26.8164 6.5546 26.7930 6.9765 26.3477 C 11.2890 21.7539 16.7031 18.8711 22.7499 17.8398 L 22.6562 11.0195 C 14.3124 12.3320 6.7656 16.5976 2.2890 21.9179 C 1.9609 22.2930 1.9843 22.8086 2.3593 23.2070 Z M 49.0702 26.3711 C 49.4686 26.7695 50.1017 26.7695 50.5702 26.3008 L 53.6407 23.2070 C 54.0391 22.8086 54.0391 22.2930 53.7108 21.9179 C 49.2343 16.5976 41.6874 12.3320 33.3437 11.0430 L 33.2734 17.8633 C 39.2968 18.9414 44.6640 21.8711 49.0702 26.3711 Z M 14.8281 35.7695 C 15.2968 36.2617 15.9062 36.2148 16.3515 35.6992 C 18.0390 33.8477 20.3359 32.3477 22.8905 31.4570 L 22.7968 24.3555 C 17.9687 25.4336 13.8437 27.9883 11.2656 31.0352 C 10.9140 31.4336 10.9609 31.9023 11.3359 32.3008 Z M 39.6952 35.7695 C 40.1405 36.2383 40.7031 36.2148 41.1952 35.7227 L 44.6640 32.3008 C 45.0390 31.9258 45.0859 31.4336 44.7343 31.0352 C 42.1562 27.9883 38.0312 25.4336 33.2265 24.3555 L 33.1562 31.5039 C 35.7109 32.4179 38.0078 33.9414 39.6952 35.7695 Z M 27.9999 48.8008 C 29.9921 48.8008 31.5624 47.1836 31.5624 45.2148 C 31.5624 43.2227 29.9921 41.6523 27.9999 41.6523 C 26.0312 41.6523 24.4140 43.2227 24.4140 45.2148 C 24.4140 47.1836 26.0312 48.8008 27.9999 48.8008 Z"/></svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -22,7 +22,7 @@ class UserSettings: ObservableObject {
|
|||
// watchOS does not provide built-in indicator, use Espera's custom indicator
|
||||
extension Indicator where T == LoadingFlowerView {
|
||||
/// Activity Indicator
|
||||
public static var activity: Indicator {
|
||||
static var activity: Indicator {
|
||||
Indicator { isAnimating, _ in
|
||||
LoadingFlowerView()
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ extension Indicator where T == LoadingFlowerView {
|
|||
|
||||
extension Indicator where T == StretchProgressView {
|
||||
/// Progress Indicator
|
||||
public static var progress: Indicator {
|
||||
static var progress: Indicator {
|
||||
Indicator { isAnimating, progress in
|
||||
StretchProgressView(progress: progress)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,31 @@
|
|||
import SwiftUI
|
||||
import SDWebImageSwiftUI
|
||||
|
||||
// Placeholder when image load failed (with `.delayPlaceholder`)
|
||||
#if !os(watchOS)
|
||||
extension PlatformImage {
|
||||
static var wifiExclamationmark: PlatformImage {
|
||||
#if os(macOS)
|
||||
return PlatformImage(named: "wifi.exclamationmark")!
|
||||
#else
|
||||
return PlatformImage(systemName: "wifi.exclamationmark")!.withTintColor(.label, renderingMode: .alwaysOriginal)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
extension Image {
|
||||
static var wifiExclamationmark: Image {
|
||||
#if os(macOS)
|
||||
return Image("wifi.exclamationmark")
|
||||
.resizable()
|
||||
#else
|
||||
return Image(systemName: "wifi.exclamationmark")
|
||||
.resizable()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct DetailView: View {
|
||||
let url: String
|
||||
let animated: Bool
|
||||
|
@ -86,19 +111,22 @@ struct DetailView: View {
|
|||
HStack {
|
||||
if animated {
|
||||
#if os(macOS) || os(iOS) || os(tvOS)
|
||||
AnimatedImage(url: URL(string:url), options: [.progressiveLoad], isAnimating: $isAnimating)
|
||||
.indicator(SDWebImageProgressIndicator.default)
|
||||
AnimatedImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder], isAnimating: $isAnimating)
|
||||
.resizable()
|
||||
.placeholder(.wifiExclamationmark)
|
||||
.indicator(SDWebImageProgressIndicator.default)
|
||||
.scaledToFit()
|
||||
#else
|
||||
WebImage(url: URL(string:url), options: [.progressiveLoad], isAnimating: $isAnimating)
|
||||
WebImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder], isAnimating: $isAnimating)
|
||||
.resizable()
|
||||
.placeholder(.wifiExclamationmark)
|
||||
.indicator(.progress)
|
||||
.scaledToFit()
|
||||
#endif
|
||||
} else {
|
||||
WebImage(url: URL(string:url), options: [.progressiveLoad])
|
||||
WebImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder])
|
||||
.resizable()
|
||||
.placeholder(.wifiExclamationmark)
|
||||
.indicator(.progress)
|
||||
.scaledToFit()
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ let package = Package(
|
|||
```swift
|
||||
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
|
||||
// Success
|
||||
}
|
||||
|
@ -155,8 +156,8 @@ var body: some View {
|
|||
```swift
|
||||
var body: some View {
|
||||
Group {
|
||||
// Network
|
||||
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"), options: [.progressiveLoad]) // Progressive Load
|
||||
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"))
|
||||
// Supports options and context, like `.progressiveLoad` for progressive animation loading
|
||||
.onFailure { error in
|
||||
// Error
|
||||
}
|
||||
|
@ -187,11 +188,13 @@ Note: `AnimatedImage` supports both image url or image data for animated image f
|
|||
Note: `AnimatedImage` some methods like `.transition`, `.indicator` and `.aspectRatio` have the same naming as `SwiftUI.View` protocol methods. But the args receive the different type. This is because `AnimatedImage` supports to be used with UIKit/AppKit component and animation. If you find ambiguity, use full type declaration instead of the dot expression syntax.
|
||||
|
||||
```swift
|
||||
AnimatedImage(name: "animation2") // Just for showcase, don't mix them at the same time
|
||||
var body: some View {
|
||||
AnimatedImage(name: "animation2") // Just for showcase, don't mix them at the same time
|
||||
.indicator(SDWebImageProgressIndicator.default) // UIKit indicator component
|
||||
.indicator(Indicator.progress) // SwiftUI indicator component
|
||||
.transition(SDWebImageTransition.flipFromLeft) // UIKit animation transition
|
||||
.transition(AnyTransition.flipFromLeft) // SwiftUI animation transition
|
||||
}
|
||||
```
|
||||
|
||||
### Which View to choose
|
||||
|
|
|
@ -106,17 +106,7 @@ public struct WebImage : View {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Group {
|
||||
if placeholder != nil {
|
||||
placeholder
|
||||
} else {
|
||||
// Should not use `EmptyView`, which does not respect to the container's frame modifier
|
||||
// Using a empty image instead for better compatible
|
||||
configurations.reduce(Image.empty) { (previous, configuration) in
|
||||
configuration(previous)
|
||||
}
|
||||
}
|
||||
}
|
||||
setupPlaceholder()
|
||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
||||
.onAppear {
|
||||
guard self.retryOnAppear else { return }
|
||||
|
@ -136,6 +126,29 @@ public struct WebImage : View {
|
|||
}
|
||||
}
|
||||
|
||||
func configure(image: Image) -> some View {
|
||||
// Should not use `EmptyView`, which does not respect to the container's frame modifier
|
||||
// Using a empty image instead for better compatible
|
||||
configurations.reduce(image) { (previous, configuration) in
|
||||
configuration(previous)
|
||||
}
|
||||
}
|
||||
|
||||
/// Placeholder View Support
|
||||
func setupPlaceholder() -> some View {
|
||||
// Don't use `Group` because it will trigger `.onAppear` and `.onDisappear` when condition view removed, treat placeholder as an entire component
|
||||
if let placeholder = placeholder {
|
||||
// If use `.delayPlaceholder`, the placeholder is applied after loading failed, hide during loading :)
|
||||
if imageManager.options.contains(.delayPlaceholder) && imageManager.isLoading {
|
||||
return AnyView(configure(image: Image.empty))
|
||||
} else {
|
||||
return placeholder
|
||||
}
|
||||
} else {
|
||||
return AnyView(configure(image: Image.empty))
|
||||
}
|
||||
}
|
||||
|
||||
/// Animated Image Support
|
||||
func setupPlayer(image: PlatformImage?) {
|
||||
if imagePlayer != nil {
|
||||
|
|
Loading…
Reference in New Issue