Skip to content

Commit 80e3137

Browse files
committed
Supports the delayPlaceholder for WebImage, update the Example to show the usage
1 parent ca9922c commit 80e3137

File tree

5 files changed

+83
-17
lines changed

5 files changed

+83
-17
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "wifi.exclamationmark.svg",
5+
"idiom" : "universal",
6+
"scale" : "1x"
7+
},
8+
{
9+
"idiom" : "universal",
10+
"scale" : "2x"
11+
},
12+
{
13+
"idiom" : "universal",
14+
"scale" : "3x"
15+
}
16+
],
17+
"info" : {
18+
"author" : "xcode",
19+
"version" : 1
20+
},
21+
"properties" : {
22+
"preserves-vector-representation" : true
23+
}
24+
}
Loading

Example/SDWebImageSwiftUIDemo/ContentView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class UserSettings: ObservableObject {
2222
// watchOS does not provide built-in indicator, use Espera's custom indicator
2323
extension Indicator where T == LoadingFlowerView {
2424
/// Activity Indicator
25-
public static var activity: Indicator {
25+
static var activity: Indicator {
2626
Indicator { isAnimating, _ in
2727
LoadingFlowerView()
2828
}
@@ -31,7 +31,7 @@ extension Indicator where T == LoadingFlowerView {
3131

3232
extension Indicator where T == StretchProgressView {
3333
/// Progress Indicator
34-
public static var progress: Indicator {
34+
static var progress: Indicator {
3535
Indicator { isAnimating, progress in
3636
StretchProgressView(progress: progress)
3737
}

Example/SDWebImageSwiftUIDemo/DetailView.swift

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,31 @@
99
import SwiftUI
1010
import SDWebImageSwiftUI
1111

12+
// Placeholder when image load failed (with `.delayPlaceholder`)
13+
#if !os(watchOS)
14+
extension PlatformImage {
15+
static var wifiExclamationmark: PlatformImage {
16+
#if os(macOS)
17+
return PlatformImage(named: "wifi.exclamationmark")!
18+
#else
19+
return PlatformImage(systemName: "wifi.exclamationmark")!.withTintColor(.label, renderingMode: .alwaysOriginal)
20+
#endif
21+
}
22+
}
23+
#endif
24+
25+
extension Image {
26+
static var wifiExclamationmark: Image {
27+
#if os(macOS)
28+
return Image("wifi.exclamationmark")
29+
.resizable()
30+
#else
31+
return Image(systemName: "wifi.exclamationmark")
32+
.resizable()
33+
#endif
34+
}
35+
}
36+
1237
struct DetailView: View {
1338
let url: String
1439
let animated: Bool
@@ -86,19 +111,22 @@ struct DetailView: View {
86111
HStack {
87112
if animated {
88113
#if os(macOS) || os(iOS) || os(tvOS)
89-
AnimatedImage(url: URL(string:url), options: [.progressiveLoad], isAnimating: $isAnimating)
90-
.indicator(SDWebImageProgressIndicator.default)
114+
AnimatedImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder], isAnimating: $isAnimating)
91115
.resizable()
116+
.placeholder(.wifiExclamationmark)
117+
.indicator(SDWebImageProgressIndicator.default)
92118
.scaledToFit()
93119
#else
94-
WebImage(url: URL(string:url), options: [.progressiveLoad], isAnimating: $isAnimating)
120+
WebImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder], isAnimating: $isAnimating)
95121
.resizable()
122+
.placeholder(.wifiExclamationmark)
96123
.indicator(.progress)
97124
.scaledToFit()
98125
#endif
99126
} else {
100-
WebImage(url: URL(string:url), options: [.progressiveLoad])
127+
WebImage(url: URL(string:url), options: [.progressiveLoad, .delayPlaceholder])
101128
.resizable()
129+
.placeholder(.wifiExclamationmark)
102130
.indicator(.progress)
103131
.scaledToFit()
104132
}

SDWebImageSwiftUI/Classes/WebImage.swift

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,7 @@ public struct WebImage : View {
106106
}
107107
}
108108
} else {
109-
Group {
110-
if placeholder != nil {
111-
placeholder
112-
} else {
113-
// Should not use `EmptyView`, which does not respect to the container's frame modifier
114-
// Using a empty image instead for better compatible
115-
configurations.reduce(Image.empty) { (previous, configuration) in
116-
configuration(previous)
117-
}
118-
}
119-
}
109+
setupPlaceholder()
120110
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
121111
.onAppear {
122112
guard self.retryOnAppear else { return }
@@ -136,6 +126,29 @@ public struct WebImage : View {
136126
}
137127
}
138128

129+
func configure(image: Image) -> some View {
130+
// Should not use `EmptyView`, which does not respect to the container's frame modifier
131+
// Using a empty image instead for better compatible
132+
configurations.reduce(image) { (previous, configuration) in
133+
configuration(previous)
134+
}
135+
}
136+
137+
/// Placeholder View Support
138+
func setupPlaceholder() -> some View {
139+
// Don't use `Group` because it will trigger `.onAppear` and `.onDisappear` when condition view removed, treat placeholder as an entire component
140+
if placeholder != nil {
141+
// If use `.delayPlaceholder`, the placeholder is applied after loading failed, hide during loading :)
142+
if imageManager.options.contains(.delayPlaceholder) && imageManager.isLoading {
143+
return AnyView(configure(image: Image.empty))
144+
} else {
145+
return AnyView(placeholder)
146+
}
147+
} else {
148+
return AnyView(configure(image: Image.empty))
149+
}
150+
}
151+
139152
/// Animated Image Support
140153
func setupPlayer(image: PlatformImage?) {
141154
if imagePlayer != nil {

0 commit comments

Comments
 (0)