@@ -44,7 +44,7 @@ final class AnimatedLoadingModel : ObservableObject, IndicatorReportable {
44
44
@Published var isLoading : Bool = false // whether network is loading or cache is querying, should only be used for indicator binding
45
45
@Published var progress : Double = 0 // network progress, should only be used for indicator binding
46
46
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)
48
48
@Published var imageName : String ?
49
49
@Published var imageData : Data ?
50
50
@Published var imageURL : URL ?
@@ -206,12 +206,27 @@ public struct AnimatedImage : PlatformViewRepresentable {
206
206
}
207
207
#endif
208
208
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 ( )
214
226
}
227
+ }
228
+
229
+ func loadImage( _ view: AnimatedImageViewWrapper , context: Context ) {
215
230
self . imageLoading. isLoading = true
216
231
let options = imageModel. webOptions
217
232
if options. contains ( . delayPlaceholder) {
@@ -234,9 +249,9 @@ public struct AnimatedImage : PlatformViewRepresentable {
234
249
self . imageHandler. progressBlock ? ( receivedSize, expectedSize)
235
250
} ) { ( image, data, error, cacheType, finished, _) in
236
251
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.
238
253
} 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
240
255
// Here I have to use UIKit/AppKit API to triger the same effect (the window change implicitly cause re-render)
241
256
if let hostingView = AnimatedImage . findHostingView ( from: view) {
242
257
if let _ = hostingView. window {
@@ -284,26 +299,28 @@ public struct AnimatedImage : PlatformViewRepresentable {
284
299
let image = SDAnimatedImage ( data: data, scale: imageModel. scale)
285
300
imageLoading. imageData = data
286
301
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
301
316
} else {
302
- view . wrapped . addSubview ( placeholderView )
317
+ shouldLoad = true
303
318
}
304
- placeholderView. bindFrameToSuperviewBounds ( )
305
319
}
306
- loadImage ( view, context: context)
320
+ if shouldLoad {
321
+ setupIndicator ( view, context: context)
322
+ loadImage ( view, context: context)
323
+ }
307
324
}
308
325
309
326
#if os(macOS)
0 commit comments