Skip to content

Commit 9cdd592

Browse files
committed
Refactory placeholder arg with a view modifier API, make it more suitable for common usage
1 parent aebd140 commit 9cdd592

File tree

2 files changed

+51
-40
lines changed

2 files changed

+51
-40
lines changed

SDWebImageSwiftUI/Classes/Indicator/Indicator.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import SwiftUI
1111

1212
/// A type to build the indicator
1313
public struct Indicator<T> where T : View {
14-
var builder: (Binding<Bool>, Binding<CGFloat>) -> T
14+
var content: (Binding<Bool>, Binding<CGFloat>) -> T
1515

1616
/// Create a indicator with builder
1717
/// - Parameter builder: A builder to build indicator
1818
/// - Parameter isAnimating: A Binding to control the animation. If image is during loading, the value is true, else (like start loading) the value is false.
1919
/// - Parameter progress: A Binding to control the progress during loading. If no progress can be reported, the value is 0.
2020
/// Associate a indicator when loading image with url
21-
public init(@ViewBuilder builder: @escaping (_ isAnimating: Binding<Bool>, _ progress: Binding<CGFloat>) -> T) {
22-
self.builder = builder
21+
public init(@ViewBuilder content: @escaping (_ isAnimating: Binding<Bool>, _ progress: Binding<CGFloat>) -> T) {
22+
self.content = content
2323
}
2424
}
2525

@@ -32,17 +32,17 @@ struct IndicatorViewModifier<T> : ViewModifier where T : View {
3232
var indicator: Indicator<T>
3333

3434
func body(content: Content) -> some View {
35-
if imageManager.isFinished {
36-
// Disable Indiactor
37-
return AnyView(content)
38-
} else {
39-
// Enable indicator
40-
return AnyView(
35+
Group {
36+
if imageManager.isFinished {
37+
// Disable Indiactor
38+
content
39+
} else {
40+
// Enable indicator
4141
ZStack {
4242
content
43-
indicator.builder($imageManager.isLoading, $imageManager.progress)
43+
indicator.content($imageManager.isLoading, $imageManager.progress)
4444
}
45-
)
45+
}
4646
}
4747
}
4848
}

SDWebImageSwiftUI/Classes/WebImage.swift

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,20 @@ public struct WebImage : View {
1313
static var emptyImage = PlatformImage()
1414

1515
var url: URL?
16-
var placeholder: Image?
1716
var options: SDWebImageOptions
1817
var context: [SDWebImageContextOption : Any]?
1918

19+
var placeholder: AnyView?
2020
var configurations: [(Image) -> Image] = []
2121

2222
@ObservedObject var imageManager: ImageManager
2323

2424
/// Create a web image with url, placeholder, custom options and context.
2525
/// - Parameter url: The image url
26-
/// - Parameter placeholder: The placeholder image to show during loading
2726
/// - Parameter options: The options to use when downloading the image. See `SDWebImageOptions` for the possible values.
2827
/// - 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.
29-
public init(url: URL?, placeholder: Image? = nil, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil) {
28+
public init(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil) {
3029
self.url = url
31-
self.placeholder = placeholder
3230
self.options = options
3331
self.context = context
3432
self.imageManager = ImageManager(url: url, options: options, context: context)
@@ -38,31 +36,31 @@ public struct WebImage : View {
3836
}
3937

4038
public var body: some View {
41-
if let platformImage = imageManager.image {
42-
var image = Image(platformImage: platformImage)
43-
image = configurations.reduce(image) { (previous, configuration) in
44-
configuration(previous)
45-
}
46-
let view = image
47-
return AnyView(view)
48-
} else {
49-
var image = placeholder ?? Image(platformImage: WebImage.emptyImage)
50-
image = configurations.reduce(image) { (previous, configuration) in
51-
configuration(previous)
52-
}
53-
let view = image
54-
.onAppear {
55-
if !self.imageManager.isFinished {
56-
self.imageManager.load()
39+
Group {
40+
if imageManager.image != nil {
41+
configurations.reduce(Image(platformImage: imageManager.image!)) { (previous, configuration) in
42+
configuration(previous)
5743
}
58-
}
59-
.onDisappear {
60-
// When using prorgessive loading, the previous partial image will cause onDisappear. Filter this case
61-
if self.imageManager.isLoading && !self.imageManager.isIncremental {
62-
self.imageManager.cancel()
44+
} else {
45+
Group {
46+
if placeholder != nil {
47+
placeholder
48+
} else {
49+
Image(platformImage: WebImage.emptyImage)
50+
}
51+
}
52+
.onAppear {
53+
if !self.imageManager.isFinished {
54+
self.imageManager.load()
55+
}
56+
}
57+
.onDisappear {
58+
// When using prorgessive loading, the previous partial image will cause onDisappear. Filter this case
59+
if self.imageManager.isLoading && !self.imageManager.isIncremental {
60+
self.imageManager.cancel()
61+
}
6362
}
6463
}
65-
return AnyView(view)
6664
}
6765
}
6866
}
@@ -135,6 +133,19 @@ extension WebImage {
135133
}
136134
}
137135

136+
// Placeholder
137+
extension WebImage {
138+
139+
/// Associate a placeholder when loading image with url
140+
/// - note: The differences between Placeholder and Indicator, is that placeholder does not supports animation, and return type is different
141+
/// - Parameter content: A view that describes the placeholder.
142+
public func placeholder<T>(@ViewBuilder _ content: () -> T) -> WebImage where T : View {
143+
var result = self
144+
result.placeholder = AnyView(content())
145+
return result
146+
}
147+
}
148+
138149
// Indicator
139150
extension WebImage {
140151

@@ -145,9 +156,9 @@ extension WebImage {
145156
}
146157

147158
/// Associate a indicator when loading image with url, convenient method with block
148-
/// - Parameter indicator: The indicator type, see `Indicator`
149-
public func indicator<T>(@ViewBuilder builder: @escaping (_ isAnimating: Binding<Bool>, _ progress: Binding<CGFloat>) -> T) -> some View where T : View {
150-
return indicator(Indicator(builder: builder))
159+
/// - Parameter content: A view that describes the indicator.
160+
public func indicator<T>(@ViewBuilder content: @escaping (_ isAnimating: Binding<Bool>, _ progress: Binding<CGFloat>) -> T) -> some View where T : View {
161+
return indicator(Indicator(content: content))
151162
}
152163
}
153164

0 commit comments

Comments
 (0)