Skip to content

Commit 66ca5fb

Browse files
committed
Update the logic to be compatible with LazyVStack's resetting status behavior
1 parent 3a7132a commit 66ca5fb

File tree

1 file changed

+42
-25
lines changed

1 file changed

+42
-25
lines changed

SDWebImageSwiftUI/Classes/AnimatedImage.swift

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ final class AnimatedLoadingModel : ObservableObject, IndicatorReportable {
4444
@Published var isLoading: Bool = false // whether network is loading or cache is querying, should only be used for indicator binding
4545
@Published var progress: Double = 0 // network progress, should only be used for indicator binding
4646

47-
/// Used for loading status recording to avoid recursive `updateView`. There are 3 types of loading (Name/Data/URL)
47+
/// Used for loading status recording to avoid recursive `updateView`. There are 3 types of loading (Name/Data/URL)
4848
@Published var imageName: String?
4949
@Published var imageData: Data?
5050
@Published var imageURL: URL?
@@ -206,12 +206,27 @@ public struct AnimatedImage : PlatformViewRepresentable {
206206
}
207207
#endif
208208

209-
func loadImage(_ view: AnimatedImageViewWrapper, context: Context) {
210-
let operationKey = NSStringFromClass(type(of: view.wrapped))
211-
let currentOperation = view.wrapped.sd_imageLoadOperation(forKey: operationKey)
212-
if currentOperation != nil {
213-
return
209+
func setupIndicator(_ view: AnimatedImageViewWrapper, context: Context) {
210+
view.wrapped.sd_imageIndicator = imageConfiguration.indicator
211+
view.wrapped.sd_imageTransition = imageConfiguration.transition
212+
if let placeholderView = imageConfiguration.placeholderView {
213+
placeholderView.removeFromSuperview()
214+
placeholderView.isHidden = true
215+
// Placeholder View should below the Indicator View
216+
if let indicatorView = imageConfiguration.indicator?.indicatorView {
217+
#if os(macOS)
218+
view.wrapped.addSubview(placeholderView, positioned: .below, relativeTo: indicatorView)
219+
#else
220+
view.wrapped.insertSubview(placeholderView, belowSubview: indicatorView)
221+
#endif
222+
} else {
223+
view.wrapped.addSubview(placeholderView)
224+
}
225+
placeholderView.bindFrameToSuperviewBounds()
214226
}
227+
}
228+
229+
func loadImage(_ view: AnimatedImageViewWrapper, context: Context) {
215230
self.imageLoading.isLoading = true
216231
let options = imageModel.webOptions
217232
if options.contains(.delayPlaceholder) {
@@ -234,9 +249,9 @@ public struct AnimatedImage : PlatformViewRepresentable {
234249
self.imageHandler.progressBlock?(receivedSize, expectedSize)
235250
}) { (image, data, error, cacheType, finished, _) in
236251
if #available(iOS 14.0, macOS 11.0, watchOS 7.0, tvOS 14.0, *) {
237-
// Do nothing
252+
// Do nothing. on iOS 14's SwiftUI, the @Published will always trigger another `updateUIView` call with new UIView instance.
238253
} else {
239-
// This is a hack because of Xcode 11.3 bug, the @Published does not trigger another `updateUIView` call
254+
// This is a hack because of iOS 13's SwiftUI bug, the @Published does not trigger another `updateUIView` call
240255
// Here I have to use UIKit/AppKit API to triger the same effect (the window change implicitly cause re-render)
241256
if let hostingView = AnimatedImage.findHostingView(from: view) {
242257
if let _ = hostingView.window {
@@ -284,26 +299,28 @@ public struct AnimatedImage : PlatformViewRepresentable {
284299
let image = SDAnimatedImage(data: data, scale: imageModel.scale)
285300
imageLoading.imageData = data
286301
view.wrapped.image = image
287-
} else if let url = imageModel.url, url != imageLoading.imageURL {
288-
imageLoading.imageURL = url
289-
view.wrapped.sd_imageIndicator = imageConfiguration.indicator
290-
view.wrapped.sd_imageTransition = imageConfiguration.transition
291-
if let placeholderView = imageConfiguration.placeholderView {
292-
placeholderView.removeFromSuperview()
293-
placeholderView.isHidden = true
294-
// Placeholder View should below the Indicator View
295-
if let indicatorView = imageConfiguration.indicator?.indicatorView {
296-
#if os(macOS)
297-
view.wrapped.addSubview(placeholderView, positioned: .below, relativeTo: indicatorView)
298-
#else
299-
view.wrapped.insertSubview(placeholderView, belowSubview: indicatorView)
300-
#endif
302+
} else if let url = imageModel.url {
303+
// Determine if image already been loaded and URL is match
304+
var shouldLoad: Bool
305+
if url != imageLoading.imageURL {
306+
// Change the URL, need new loading
307+
shouldLoad = true
308+
imageLoading.imageURL = url
309+
} else {
310+
// Same URL, check if already loaded
311+
if imageLoading.isLoading {
312+
shouldLoad = false
313+
} else if let image = imageLoading.image {
314+
shouldLoad = false
315+
view.wrapped.image = image
301316
} else {
302-
view.wrapped.addSubview(placeholderView)
317+
shouldLoad = true
303318
}
304-
placeholderView.bindFrameToSuperviewBounds()
305319
}
306-
loadImage(view, context: context)
320+
if shouldLoad {
321+
setupIndicator(view, context: context)
322+
loadImage(view, context: context)
323+
}
307324
}
308325

309326
#if os(macOS)

0 commit comments

Comments
 (0)