Skip to content

Commit 0fd18bc

Browse files
committed
Fix the issue for AnimatedImage when url is nil will not cause the reloading
1 parent 4c4b868 commit 0fd18bc

File tree

2 files changed

+76
-50
lines changed

2 files changed

+76
-50
lines changed

‎Example/SDWebImageSwiftUIDemo/ContentView.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class UserSettings: ObservableObject {
1818
}
1919

2020
// Test Switching nil url
21-
struct ContentView: View {
21+
struct ContentView3: View {
2222
@State var isOn = false
2323
@State var animated: Bool = false // You can change between WebImage/AnimatedImage
2424

@@ -100,7 +100,7 @@ struct ContentView2: View {
100100
}
101101
}
102102

103-
struct ContentView3: View {
103+
struct ContentView: View {
104104
@State var imageURLs = [
105105
"http://assets.sbnation.com/assets/2512203/dogflops.gif",
106106
"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif",

‎SDWebImageSwiftUI/Classes/AnimatedImage.swift

+74-48
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ public final class AnimatedImageCoordinator: NSObject {
2727
/// Data Binding Object, only properties in this object can support changes from user with @State and refresh
2828
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
2929
final class AnimatedImageModel : ObservableObject {
30+
enum Kind {
31+
case url
32+
case data
33+
case name
34+
case unknown
35+
}
36+
var kind: Kind = .unknown
3037
/// URL image
3138
@Published var url: URL?
3239
@Published var webOptions: SDWebImageOptions = []
@@ -123,6 +130,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
123130
/// - Parameter isAnimating: The binding for animation control
124131
public init(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil, isAnimating: Binding<Bool> = .constant(true), placeholderImage: PlatformImage? = nil) {
125132
let imageModel = AnimatedImageModel()
133+
imageModel.kind = .url
126134
imageModel.url = url
127135
imageModel.webOptions = options
128136
imageModel.webContext = context
@@ -138,6 +146,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
138146
/// - Parameter isAnimating: The binding for animation control
139147
public init<T>(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil, isAnimating: Binding<Bool> = .constant(true), @ViewBuilder placeholder: @escaping () -> T) where T : View {
140148
let imageModel = AnimatedImageModel()
149+
imageModel.kind = .url
141150
imageModel.url = url
142151
imageModel.webOptions = options
143152
imageModel.webContext = context
@@ -157,6 +166,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
157166
/// - Parameter isAnimating: The binding for animation control
158167
public init(name: String, bundle: Bundle? = nil, isAnimating: Binding<Bool> = .constant(true)) {
159168
let imageModel = AnimatedImageModel()
169+
imageModel.kind = .name
160170
imageModel.name = name
161171
imageModel.bundle = bundle
162172
self.init(imageModel: imageModel, isAnimating: isAnimating)
@@ -168,6 +178,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
168178
/// - Parameter isAnimating: The binding for animation control
169179
public init(data: Data, scale: CGFloat = 1, isAnimating: Binding<Bool> = .constant(true)) {
170180
let imageModel = AnimatedImageModel()
181+
imageModel.kind = .data
171182
imageModel.data = data
172183
imageModel.scale = scale
173184
self.init(imageModel: imageModel, isAnimating: isAnimating)
@@ -275,57 +286,72 @@ public struct AnimatedImage : PlatformViewRepresentable {
275286
return view
276287
}
277288

289+
private func updateViewForName(_ name: String, view: AnimatedImageViewWrapper, context: Context) {
290+
var image: PlatformImage?
291+
#if os(macOS)
292+
image = SDAnimatedImage(named: name, in: imageModel.bundle)
293+
if image == nil {
294+
// For static image, use NSImage as defaults
295+
let bundle = imageModel.bundle ?? .main
296+
image = bundle.image(forResource: name)
297+
}
298+
#else
299+
image = SDAnimatedImage(named: name, in: imageModel.bundle, compatibleWith: nil)
300+
if image == nil {
301+
// For static image, use UIImage as defaults
302+
image = PlatformImage(named: name, in: imageModel.bundle, compatibleWith: nil)
303+
}
304+
#endif
305+
context.coordinator.imageLoading.imageName = name
306+
view.wrapped.image = image
307+
}
308+
309+
private func updateViewForData(_ data: Data, view: AnimatedImageViewWrapper, context: Context) {
310+
var image: PlatformImage? = SDAnimatedImage(data: data, scale: imageModel.scale)
311+
if image == nil {
312+
// For static image, use UIImage as defaults
313+
image = PlatformImage.sd_image(with: data, scale: imageModel.scale)
314+
}
315+
context.coordinator.imageLoading.imageData = data
316+
view.wrapped.image = image
317+
}
318+
319+
private func updateViewForURL(_ url: URL?, view: AnimatedImageViewWrapper, context: Context) {
320+
// Determine if image already been loaded and URL is match
321+
var shouldLoad: Bool
322+
if url != context.coordinator.imageLoading.imageURL {
323+
// Change the URL, need new loading
324+
shouldLoad = true
325+
context.coordinator.imageLoading.imageURL = url
326+
} else {
327+
// Same URL, check if already loaded
328+
if context.coordinator.imageLoading.isLoading {
329+
shouldLoad = false
330+
} else if let image = context.coordinator.imageLoading.image {
331+
shouldLoad = false
332+
view.wrapped.image = image
333+
} else {
334+
shouldLoad = true
335+
}
336+
}
337+
if shouldLoad {
338+
setupIndicator(view, context: context)
339+
loadImage(view, context: context)
340+
}
341+
}
342+
278343
func updateView(_ view: AnimatedImageViewWrapper, context: Context) {
279344
// Refresh image, imageModel is the Source of Truth, switch the type
280345
// Although we have Source of Truth, we can check the previous value, to avoid re-generate SDAnimatedImage, which is performance-cost.
281-
if let name = imageModel.name, name != context.coordinator.imageLoading.imageName {
282-
var image: PlatformImage?
283-
#if os(macOS)
284-
image = SDAnimatedImage(named: name, in: imageModel.bundle)
285-
if image == nil {
286-
// For static image, use NSImage as defaults
287-
let bundle = imageModel.bundle ?? .main
288-
image = bundle.image(forResource: name)
289-
}
290-
#else
291-
image = SDAnimatedImage(named: name, in: imageModel.bundle, compatibleWith: nil)
292-
if image == nil {
293-
// For static image, use UIImage as defaults
294-
image = PlatformImage(named: name, in: imageModel.bundle, compatibleWith: nil)
295-
}
296-
#endif
297-
context.coordinator.imageLoading.imageName = name
298-
view.wrapped.image = image
299-
} else if let data = imageModel.data, data != context.coordinator.imageLoading.imageData {
300-
var image: PlatformImage? = SDAnimatedImage(data: data, scale: imageModel.scale)
301-
if image == nil {
302-
// For static image, use UIImage as defaults
303-
image = PlatformImage.sd_image(with: data, scale: imageModel.scale)
304-
}
305-
context.coordinator.imageLoading.imageData = data
306-
view.wrapped.image = image
307-
} else if let url = imageModel.url {
308-
// Determine if image already been loaded and URL is match
309-
var shouldLoad: Bool
310-
if url != context.coordinator.imageLoading.imageURL {
311-
// Change the URL, need new loading
312-
shouldLoad = true
313-
context.coordinator.imageLoading.imageURL = url
314-
} else {
315-
// Same URL, check if already loaded
316-
if context.coordinator.imageLoading.isLoading {
317-
shouldLoad = false
318-
} else if let image = context.coordinator.imageLoading.image {
319-
shouldLoad = false
320-
view.wrapped.image = image
321-
} else {
322-
shouldLoad = true
323-
}
324-
}
325-
if shouldLoad {
326-
setupIndicator(view, context: context)
327-
loadImage(view, context: context)
328-
}
346+
let kind = imageModel.kind
347+
if kind == .name, let name = imageModel.name, name != context.coordinator.imageLoading.imageName {
348+
updateViewForName(name, view: view, context: context)
349+
} else if kind == .data, let data = imageModel.data, data != context.coordinator.imageLoading.imageData {
350+
updateViewForData(data, view: view, context: context)
351+
} else if kind == .url {
352+
updateViewForURL(imageModel.url, view: view, context: context)
353+
} else {
354+
fatalError("Unsupport model kind: \(kind)")
329355
}
330356

331357
#if os(macOS)

0 commit comments

Comments
 (0)