@@ -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 , * )
2929final 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 ( " Unsupported model kind: \( kind) " )
329355 }
330356
331357 #if os(macOS)
0 commit comments