From fb7d3919b4eb7960ff3636dc9008028656c81a16 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 2 Nov 2019 16:11:01 +0800 Subject: [PATCH 1/5] Rmove the unused cross-platforms alias --- SDWebImageSwiftUI/Classes/SDWebImageSwiftUI.swift | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/SDWebImageSwiftUI/Classes/SDWebImageSwiftUI.swift b/SDWebImageSwiftUI/Classes/SDWebImageSwiftUI.swift index 1f434f24..bca01237 100644 --- a/SDWebImageSwiftUI/Classes/SDWebImageSwiftUI.swift +++ b/SDWebImageSwiftUI/Classes/SDWebImageSwiftUI.swift @@ -36,14 +36,11 @@ public typealias PlatformView = WKInterfaceObject #endif #if os(macOS) -typealias PlatformViewRepresentable = NSViewRepresentable -typealias PlatformViewRepresentableContext = NSViewRepresentableContext +public typealias PlatformViewRepresentable = NSViewRepresentable #endif #if os(iOS) || os(tvOS) -typealias PlatformViewRepresentable = UIViewRepresentable -typealias PlatformViewRepresentableContext = UIViewRepresentableContext +public typealias PlatformViewRepresentable = UIViewRepresentable #endif #if os(watchOS) -typealias PlatformViewRepresentable = WKInterfaceObjectRepresentable -typealias PlatformViewRepresentableContext = WKInterfaceObjectRepresentableContext +public typealias PlatformViewRepresentable = WKInterfaceObjectRepresentable #endif From 3579e7b7f12ec64a43adbf5e0df373b926920dd1 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 2 Nov 2019 16:22:14 +0800 Subject: [PATCH 2/5] Add `onViewDestroy` API, change `onViewUpdate` and `onViewCreate` with context arg to pass user-provided value. Chaing all the unused binding into the stored property --- SDWebImageSwiftUI/Classes/AnimatedImage.swift | 243 ++++++++++-------- 1 file changed, 141 insertions(+), 102 deletions(-) diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index 5115b624..e1ca1c7b 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -15,39 +15,6 @@ import SDWebImageSwiftUIObjC // Data Binding Object final class AnimatedImageModel : ObservableObject { @Published var image: PlatformImage? - @Published var successBlock: ((PlatformImage, SDImageCacheType) -> Void)? - @Published var failureBlock: ((Error) -> Void)? - @Published var progressBlock: ((Int, Int) -> Void)? -} - -// Coordinator Life Cycle Binding Object -final class AnimatedImageCoordinator : ObservableObject { - @Published var viewCreateBlock: ((PlatformView) -> Void)? - @Published var viewUpdateBlock: ((PlatformView) -> Void)? -} - -// Layout Binding Object -final class AnimatedImageLayout : ObservableObject { - @Published var contentMode: ContentMode? - @Published var aspectRatio: CGFloat? - @Published var capInsets: EdgeInsets = EdgeInsets() - @Published var resizingMode: Image.ResizingMode? - @Published var renderingMode: Image.TemplateRenderingMode? - @Published var interpolation: Image.Interpolation? - @Published var antialiased: Bool = false -} - -// Configuration Binding Object -final class AnimatedImageConfiguration: ObservableObject { - @Published var incrementalLoad: Bool? - @Published var maxBufferSize: UInt? - @Published var customLoopCount: Int? - #if os(macOS) || os(iOS) || os(tvOS) - // These configurations only useful for web image loading - @Published var indicator: SDWebImageIndicator? - @Published var transition: SDWebImageTransition? - #endif - @Published var placeholder: PlatformImage? } // Convenient @@ -60,21 +27,64 @@ extension SDAnimatedImageInterface { } #endif +// Coordinator Life Cycle Binding Object +public final class AnimatedImageCoordinator: NSObject { + + /// Any user-provided object for actual coordinator, such as delegate method, taget-action + public var object: Any? + + /// Any user-provided info stored into coordinator, such as status value used for coordinator + public var userInfo: [AnyHashable : Any]? +} + // View public struct AnimatedImage : PlatformViewRepresentable { @ObservedObject var imageModel = AnimatedImageModel() - @ObservedObject var imageLayout = AnimatedImageLayout() - @ObservedObject var imageConfiguration = AnimatedImageConfiguration() - @ObservedObject var imageCoordinator = AnimatedImageCoordinator() + // Options var url: URL? var webOptions: SDWebImageOptions = [] var webContext: [SDWebImageContextOption : Any]? = nil + // Completion Handler + var successBlock: ((PlatformImage, SDImageCacheType) -> Void)? + var failureBlock: ((Error) -> Void)? + var progressBlock: ((Int, Int) -> Void)? + + // Layout + var contentMode: ContentMode? + var aspectRatio: CGFloat? + var capInsets: EdgeInsets = EdgeInsets() + var resizingMode: Image.ResizingMode? + var renderingMode: Image.TemplateRenderingMode? + var interpolation: Image.Interpolation? + var antialiased: Bool = false + + // Configuration + var incrementalLoad: Bool? + var maxBufferSize: UInt? + var customLoopCount: Int? + #if os(macOS) || os(iOS) || os(tvOS) + // These configurations only useful for web image loading + var indicator: SDWebImageIndicator? + var transition: SDWebImageTransition? + #endif + var placeholder: PlatformImage? + + // Coordinator + var viewCreateBlock: ((PlatformView, PlatformViewRepresentableContext) -> Void)? + var viewUpdateBlock: ((PlatformView, PlatformViewRepresentableContext) -> Void)? + static var viewDestroyBlock: ((PlatformView, Coordinator) -> Void)? + /// A Binding to control the animation. You can bind external logic to control the animation status. /// True to start animation, false to stop animation. @Binding public var isAnimating: Bool + /// Current loaded image, may be `SDAnimatedImage` type + public var image: PlatformImage? { + imageModel.image + } + /// Create an animated image with url, placeholder, custom options and context. /// - Parameter url: The image url /// - Parameter placeholder: The placeholder image to show during loading @@ -145,6 +155,12 @@ public struct AnimatedImage : PlatformViewRepresentable { public typealias WKInterfaceObjectType = AnimatedImageViewWrapper #endif + public typealias Coordinator = AnimatedImageCoordinator + + public func makeCoordinator() -> Coordinator { + AnimatedImageCoordinator() + } + #if os(macOS) public func makeNSView(context: NSViewRepresentableContext) -> AnimatedImageViewWrapper { makeView(context: context) @@ -154,7 +170,7 @@ public struct AnimatedImage : PlatformViewRepresentable { updateView(nsView, context: context) } - public static func dismantleNSView(_ nsView: AnimatedImageViewWrapper, coordinator: ()) { + public static func dismantleNSView(_ nsView: AnimatedImageViewWrapper, coordinator: Coordinator) { dismantleView(nsView, coordinator: coordinator) } #elseif os(iOS) || os(tvOS) @@ -166,7 +182,7 @@ public struct AnimatedImage : PlatformViewRepresentable { updateView(uiView, context: context) } - public static func dismantleUIView(_ uiView: AnimatedImageViewWrapper, coordinator: ()) { + public static func dismantleUIView(_ uiView: AnimatedImageViewWrapper, coordinator: Coordinator) { dismantleView(uiView, coordinator: coordinator) } #elseif os(watchOS) @@ -178,7 +194,7 @@ public struct AnimatedImage : PlatformViewRepresentable { updateView(wkInterfaceObject, context: context) } - public static func dismantleWKInterfaceObject(_ wkInterfaceObject: AnimatedImageViewWrapper, coordinator: ()) { + public static func dismantleWKInterfaceObject(_ wkInterfaceObject: AnimatedImageViewWrapper, coordinator: Coordinator) { dismantleView(wkInterfaceObject, coordinator: coordinator) } #endif @@ -189,22 +205,22 @@ public struct AnimatedImage : PlatformViewRepresentable { if currentOperation != nil { return } - view.wrapped.sd_setImage(with: url, placeholderImage: imageConfiguration.placeholder, options: webOptions, context: webContext, progress: { (receivedSize, expectedSize, _) in - self.imageModel.progressBlock?(receivedSize, expectedSize) + view.wrapped.sd_setImage(with: url, placeholderImage: placeholder, options: webOptions, context: webContext, progress: { (receivedSize, expectedSize, _) in + self.progressBlock?(receivedSize, expectedSize) }) { (image, error, cacheType, _) in if let image = image { self.imageModel.image = image - self.imageModel.successBlock?(image, cacheType) + self.successBlock?(image, cacheType) } else { - self.imageModel.failureBlock?(error ?? NSError()) + self.failureBlock?(error ?? NSError()) } } } func makeView(context: PlatformViewRepresentableContext) -> AnimatedImageViewWrapper { let view = AnimatedImageViewWrapper() - if let viewCreateBlock = imageCoordinator.viewCreateBlock { - viewCreateBlock(view) + if let viewCreateBlock = viewCreateBlock { + viewCreateBlock(view.wrapped, context) } return view } @@ -215,7 +231,7 @@ public struct AnimatedImage : PlatformViewRepresentable { view.wrapped.animates = true #endif - if let image = imageModel.image { + if let image = self.imageModel.image { #if os(watchOS) view.wrapped.setImage(image) #else @@ -224,8 +240,8 @@ public struct AnimatedImage : PlatformViewRepresentable { } else { if let url = url { #if os(macOS) || os(iOS) || os(tvOS) - view.wrapped.sd_imageIndicator = imageConfiguration.indicator - view.wrapped.sd_imageTransition = imageConfiguration.transition + view.wrapped.sd_imageIndicator = self.indicator + view.wrapped.sd_imageTransition = self.transition #endif loadImage(view, url: url) } @@ -252,18 +268,21 @@ public struct AnimatedImage : PlatformViewRepresentable { configureView(view, context: context) layoutView(view, context: context) - if let viewUpdateBlock = imageCoordinator.viewUpdateBlock { - viewUpdateBlock(view) + if let viewUpdateBlock = viewUpdateBlock { + viewUpdateBlock(view.wrapped, context) } } - static func dismantleView(_ view: AnimatedImageViewWrapper, coordinator: ()) { + static func dismantleView(_ view: AnimatedImageViewWrapper, coordinator: Coordinator) { view.wrapped.sd_cancelCurrentImageLoad() #if os(macOS) view.wrapped.animates = false #else view.wrapped.stopAnimating() #endif + if let viewDestroyBlock = viewDestroyBlock { + viewDestroyBlock(view.wrapped, coordinator) + } } func layoutView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext) { @@ -275,7 +294,7 @@ public struct AnimatedImage : PlatformViewRepresentable { #elseif os(watchOS) let contentMode: SDImageScaleMode #endif - if let _ = imageLayout.aspectRatio { + if let _ = self.aspectRatio { // If `aspectRatio` is not `nil`, always scale to fill and SwiftUI will layout the container with custom aspect ratio. #if os(macOS) contentMode = .scaleAxesIndependently @@ -286,7 +305,7 @@ public struct AnimatedImage : PlatformViewRepresentable { #endif } else { // If `aspectRatio` is `nil`, the resulting view maintains this view's aspect ratio. - switch imageLayout.contentMode { + switch self.contentMode { case .fill: #if os(macOS) // Actually, NSImageView have no `.aspectFill` unlike UIImageView, only `CALayerContentsGravity.resizeAspectFill` have the same concept @@ -326,14 +345,14 @@ public struct AnimatedImage : PlatformViewRepresentable { #endif // Animated Image does not support resizing mode and rendering mode - if let image = imageModel.image, !image.sd_isAnimated, !image.conforms(to: SDAnimatedImageProtocol.self) { + if let image = self.imageModel.image, !image.sd_isAnimated, !image.conforms(to: SDAnimatedImageProtocol.self) { var image = image // ResizingMode - if let resizingMode = imageLayout.resizingMode { + if let resizingMode = self.resizingMode { #if os(macOS) - let capInsets = NSEdgeInsets(top: imageLayout.capInsets.top, left: imageLayout.capInsets.leading, bottom: imageLayout.capInsets.bottom, right: imageLayout.capInsets.trailing) + let capInsets = NSEdgeInsets(top: self.capInsets.top, left: self.capInsets.leading, bottom: self.capInsets.bottom, right: self.capInsets.trailing) #else - let capInsets = UIEdgeInsets(top: imageLayout.capInsets.top, left: imageLayout.capInsets.leading, bottom: imageLayout.capInsets.bottom, right: imageLayout.capInsets.trailing) + let capInsets = UIEdgeInsets(top: self.capInsets.top, left: self.capInsets.leading, bottom: self.capInsets.bottom, right: self.capInsets.trailing) #endif switch resizingMode { case .stretch: @@ -367,7 +386,7 @@ public struct AnimatedImage : PlatformViewRepresentable { } // RenderingMode - if let renderingMode = imageLayout.renderingMode { + if let renderingMode = self.renderingMode { switch renderingMode { case .template: #if os(macOS) @@ -400,7 +419,7 @@ public struct AnimatedImage : PlatformViewRepresentable { #if os(macOS) || os(iOS) || os(tvOS) // Interpolation - if let interpolation = imageLayout.interpolation { + if let interpolation = self.interpolation { switch interpolation { case .high: view.interpolationQuality = .high @@ -419,19 +438,19 @@ public struct AnimatedImage : PlatformViewRepresentable { } // Antialiased - view.shouldAntialias = imageLayout.antialiased + view.shouldAntialias = self.antialiased #endif } func configureView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext) { #if os(macOS) || os(iOS) || os(tvOS) // IncrementalLoad - if let incrementalLoad = imageConfiguration.incrementalLoad { + if let incrementalLoad = self.incrementalLoad { view.wrapped.shouldIncrementalLoad = incrementalLoad } // MaxBufferSize - if let maxBufferSize = imageConfiguration.maxBufferSize { + if let maxBufferSize = self.maxBufferSize { view.wrapped.maxBufferSize = maxBufferSize } else { // automatically @@ -439,7 +458,7 @@ public struct AnimatedImage : PlatformViewRepresentable { } // CustomLoopCount - if let customLoopCount = imageConfiguration.customLoopCount { + if let customLoopCount = self.customLoopCount { view.wrapped.shouldCustomLoopCount = true view.wrapped.animationRepeatCount = customLoopCount } else { @@ -447,7 +466,7 @@ public struct AnimatedImage : PlatformViewRepresentable { view.wrapped.shouldCustomLoopCount = false } #elseif os(watchOS) - if let customLoopCount = imageConfiguration.customLoopCount { + if let customLoopCount = self.customLoopCount { view.wrapped.setAnimationRepeatCount(customLoopCount as NSNumber) } else { // disable custom loop count @@ -468,31 +487,35 @@ extension AnimatedImage { capInsets: EdgeInsets = EdgeInsets(), resizingMode: Image.ResizingMode = .stretch) -> AnimatedImage { - imageLayout.capInsets = capInsets - imageLayout.resizingMode = resizingMode - return self + var result = self + result.capInsets = capInsets + result.resizingMode = resizingMode + return result } /// Configurate this view's rendering mode. /// - Warning: Animated Image does not implementes. /// - Parameter renderingMode: The resizing mode public func renderingMode(_ renderingMode: Image.TemplateRenderingMode?) -> AnimatedImage { - imageLayout.renderingMode = renderingMode - return self + var result = self + result.renderingMode = renderingMode + return result } /// Configurate this view's image interpolation quality /// - Parameter interpolation: The interpolation quality public func interpolation(_ interpolation: Image.Interpolation) -> AnimatedImage { - imageLayout.interpolation = interpolation - return self + var result = self + result.interpolation = interpolation + return result } /// Configurate this view's image antialiasing /// - Parameter isAntialiased: Whether or not to allow antialiasing public func antialiased(_ isAntialiased: Bool) -> AnimatedImage { - imageLayout.antialiased = isAntialiased - return self + var result = self + result.antialiased = isAntialiased + return result } } @@ -516,18 +539,19 @@ extension AnimatedImage { // But 2: there are no way to call a Protocol Extention default implementation in Swift 5.1 // So, we need a hack, that create a empty modifier, they call method on that view instead // Fired Radar: FB7413534 - imageLayout.aspectRatio = aspectRatio - imageLayout.contentMode = contentMode + var result = self + result.aspectRatio = aspectRatio + result.contentMode = contentMode #if os(macOS) || os(iOS) || os(tvOS) - return self.modifier(EmptyModifier()).aspectRatio(aspectRatio, contentMode: contentMode) + return result.modifier(EmptyModifier()).aspectRatio(aspectRatio, contentMode: contentMode) #else return Group { if aspectRatio != nil { - self.modifier(EmptyModifier()).aspectRatio(aspectRatio, contentMode: contentMode) + result.modifier(EmptyModifier()).aspectRatio(aspectRatio, contentMode: contentMode) } else { // on watchOS, there are no workaround like `AnimatedImageViewWrapper` to override `intrinsicContentSize`, so the aspect ratio is undetermined and cause sizing issues // To workaround, we do not call default implementation for this case, using original solution instead - self + result } } #endif @@ -573,8 +597,9 @@ extension AnimatedImage { /// - Note: Pass nil to disable customization, use the image itself loop count (`animatedImageLoopCount`) instead /// - Parameter loopCount: The animation loop count public func customLoopCount(_ loopCount: Int?) -> AnimatedImage { - imageConfiguration.customLoopCount = loopCount - return self + var result = self + result.customLoopCount = loopCount + return result } /// Provide a max buffer size by bytes. This is used to adjust frame buffer count and can be useful when the decoding cost is expensive (such as Animated WebP software decoding). Default is nil. @@ -585,8 +610,9 @@ extension AnimatedImage { /// - Warning: watchOS does not implementes. /// - Parameter bufferSize: The max buffer size public func maxBufferSize(_ bufferSize: UInt?) -> AnimatedImage { - imageConfiguration.maxBufferSize = bufferSize - return self + var result = self + result.maxBufferSize = bufferSize + return result } /// Whehter or not to enable incremental image load for animated image. See `SDAnimatedImageView` for detailed explanation for this. @@ -595,8 +621,9 @@ extension AnimatedImage { /// - Warning: watchOS does not implementes. /// - Parameter incrementalLoad: Whether or not to incremental load public func incrementalLoad(_ incrementalLoad: Bool) -> AnimatedImage { - imageConfiguration.incrementalLoad = incrementalLoad - return self + var result = self + result.incrementalLoad = incrementalLoad + return result } } @@ -608,8 +635,9 @@ extension AnimatedImage { /// - action: The action to perform. The first arg is the error during loading. If `action` is `nil`, the call has no effect. /// - Returns: A view that triggers `action` when this image load fails. public func onFailure(perform action: ((Error) -> Void)? = nil) -> AnimatedImage { - imageModel.failureBlock = action - return self + var result = self + result.failureBlock = action + return result } /// Provide the action when image load successes. @@ -617,8 +645,9 @@ extension AnimatedImage { /// - action: The action to perform. The first arg is the loaded image, the second arg is the cache type loaded from. If `action` is `nil`, the call has no effect. /// - Returns: A view that triggers `action` when this image load successes. public func onSuccess(perform action: ((PlatformImage, SDImageCacheType) -> Void)? = nil) -> AnimatedImage { - imageModel.successBlock = action - return self + var result = self + result.successBlock = action + return result } /// Provide the action when image load progress changes. @@ -626,8 +655,9 @@ extension AnimatedImage { /// - action: The action to perform. The first arg is the received size, the second arg is the total size, all in bytes. If `action` is `nil`, the call has no effect. /// - Returns: A view that triggers `action` when this image load successes. public func onProgress(perform action: ((Int, Int) -> Void)? = nil) -> AnimatedImage { - imageModel.progressBlock = action - return self + var result = self + result.progressBlock = action + return result } } @@ -637,17 +667,23 @@ extension AnimatedImage { /// Provide the action when view representable create the native view. /// - Parameter action: The action to perform. The first arg is the native view. /// - Returns: A view that triggers `action` when view representable create the native view. - public func onViewCreate(perform action: ((PlatformView) -> Void)? = nil) -> AnimatedImage { - imageCoordinator.viewCreateBlock = action - return self + public func onViewCreate(perform action: ((PlatformView, PlatformViewRepresentableContext) -> Void)? = nil) -> AnimatedImage { + var result = self + result.viewCreateBlock = action + return result } /// Provide the action when view representable update the native view. /// - Parameter action: The action to perform. The first arg is the native view. /// - Returns: A view that triggers `action` when view representable update the native view. - public func onViewUpdate(perform action: ((PlatformView) -> Void)? = nil) -> AnimatedImage { - imageCoordinator.viewUpdateBlock = action - return self + public func onViewUpdate(perform action: ((PlatformView, PlatformViewRepresentableContext) -> Void)? = nil) -> AnimatedImage { + var result = self + result.viewUpdateBlock = action + return result + } + + public static func onViewDestroy(perform action: ((PlatformView, Coordinator) -> Void)? = nil) { + self.viewDestroyBlock = action } } @@ -657,8 +693,9 @@ extension AnimatedImage { /// Associate a placeholder when loading image with url /// - Parameter content: A view that describes the placeholder. public func placeholder(_ placeholder: PlatformImage?) -> AnimatedImage { - imageConfiguration.placeholder = placeholder - return self + var result = self + result.placeholder = placeholder + return result } #if os(macOS) || os(iOS) || os(tvOS) @@ -666,16 +703,18 @@ extension AnimatedImage { /// - Note: If you do not need indicator, specify nil. Defaults to nil /// - Parameter indicator: indicator, see more in `SDWebImageIndicator` public func indicator(_ indicator: SDWebImageIndicator?) -> AnimatedImage { - imageConfiguration.indicator = indicator - return self + var result = self + result.indicator = indicator + return result } /// Associate a transition when loading image with url /// - Note: If you specify nil, do not do transition. Defautls to nil. /// - Parameter transition: transition, see more in `SDWebImageTransition` public func transition(_ transition: SDWebImageTransition?) -> AnimatedImage { - imageConfiguration.transition = transition - return self + var result = self + result.transition = transition + return result } #endif } From f10bfa77773a91b9414597c10cf3116fb36e1583 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 2 Nov 2019 16:24:43 +0800 Subject: [PATCH 3/5] Update the code documentation for AnimatedImage --- SDWebImageSwiftUI/Classes/AnimatedImage.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index e1ca1c7b..ba21d408 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -665,7 +665,7 @@ extension AnimatedImage { extension AnimatedImage { /// Provide the action when view representable create the native view. - /// - Parameter action: The action to perform. The first arg is the native view. + /// - Parameter action: The action to perform. The first arg is the native view. The seconds arg is the context. /// - Returns: A view that triggers `action` when view representable create the native view. public func onViewCreate(perform action: ((PlatformView, PlatformViewRepresentableContext) -> Void)? = nil) -> AnimatedImage { var result = self @@ -674,7 +674,7 @@ extension AnimatedImage { } /// Provide the action when view representable update the native view. - /// - Parameter action: The action to perform. The first arg is the native view. + /// - Parameter action: The action to perform. The first arg is the native view. The seconds arg is the context. /// - Returns: A view that triggers `action` when view representable update the native view. public func onViewUpdate(perform action: ((PlatformView, PlatformViewRepresentableContext) -> Void)? = nil) -> AnimatedImage { var result = self @@ -682,6 +682,9 @@ extension AnimatedImage { return result } + /// Provide the action when view representable destroy the native view + /// - Parameter action: The action to perform. The first arg is the native view. The seconds arg is the coordinator (with userInfo). + /// - Returns: A view that triggers `action` when view representable destroy the native view. public static func onViewDestroy(perform action: ((PlatformView, Coordinator) -> Void)? = nil) { self.viewDestroyBlock = action } From 03982673cabaf8efd8b0e86b4c3bc784455a6d5c Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 2 Nov 2019 16:27:38 +0800 Subject: [PATCH 4/5] Simplify the type declaration --- SDWebImageSwiftUI/Classes/AnimatedImage.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index ba21d408..5defc83f 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -72,8 +72,8 @@ public struct AnimatedImage : PlatformViewRepresentable { var placeholder: PlatformImage? // Coordinator - var viewCreateBlock: ((PlatformView, PlatformViewRepresentableContext) -> Void)? - var viewUpdateBlock: ((PlatformView, PlatformViewRepresentableContext) -> Void)? + var viewCreateBlock: ((PlatformView, Context) -> Void)? + var viewUpdateBlock: ((PlatformView, Context) -> Void)? static var viewDestroyBlock: ((PlatformView, Coordinator) -> Void)? /// A Binding to control the animation. You can bind external logic to control the animation status. @@ -217,7 +217,7 @@ public struct AnimatedImage : PlatformViewRepresentable { } } - func makeView(context: PlatformViewRepresentableContext) -> AnimatedImageViewWrapper { + func makeView(context: Context) -> AnimatedImageViewWrapper { let view = AnimatedImageViewWrapper() if let viewCreateBlock = viewCreateBlock { viewCreateBlock(view.wrapped, context) @@ -225,7 +225,7 @@ public struct AnimatedImage : PlatformViewRepresentable { return view } - func updateView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext) { + func updateView(_ view: AnimatedImageViewWrapper, context: Context) { // macOS SDAnimatedImageView.animates should initialize to true in advance before set image #if os(macOS) view.wrapped.animates = true @@ -285,7 +285,7 @@ public struct AnimatedImage : PlatformViewRepresentable { } } - func layoutView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext) { + func layoutView(_ view: AnimatedImageViewWrapper, context: Context) { // AspectRatio && ContentMode #if os(macOS) let contentMode: NSImageScaling @@ -442,7 +442,7 @@ public struct AnimatedImage : PlatformViewRepresentable { #endif } - func configureView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext) { + func configureView(_ view: AnimatedImageViewWrapper, context: Context) { #if os(macOS) || os(iOS) || os(tvOS) // IncrementalLoad if let incrementalLoad = self.incrementalLoad { @@ -667,7 +667,7 @@ extension AnimatedImage { /// Provide the action when view representable create the native view. /// - Parameter action: The action to perform. The first arg is the native view. The seconds arg is the context. /// - Returns: A view that triggers `action` when view representable create the native view. - public func onViewCreate(perform action: ((PlatformView, PlatformViewRepresentableContext) -> Void)? = nil) -> AnimatedImage { + public func onViewCreate(perform action: ((PlatformView, Context) -> Void)? = nil) -> AnimatedImage { var result = self result.viewCreateBlock = action return result @@ -676,7 +676,7 @@ extension AnimatedImage { /// Provide the action when view representable update the native view. /// - Parameter action: The action to perform. The first arg is the native view. The seconds arg is the context. /// - Returns: A view that triggers `action` when view representable update the native view. - public func onViewUpdate(perform action: ((PlatformView, PlatformViewRepresentableContext) -> Void)? = nil) -> AnimatedImage { + public func onViewUpdate(perform action: ((PlatformView, Context) -> Void)? = nil) -> AnimatedImage { var result = self result.viewUpdateBlock = action return result From 04fc21a08cc41df51800da856fbfaa0d5349843e Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 2 Nov 2019 16:39:56 +0800 Subject: [PATCH 5/5] Add the comments about how to use native view update helper --- Example/SDWebImageSwiftUIDemo/ContentView.swift | 5 +++++ README.md | 3 +++ 2 files changed, 8 insertions(+) diff --git a/Example/SDWebImageSwiftUIDemo/ContentView.swift b/Example/SDWebImageSwiftUIDemo/ContentView.swift index cc3b339a..04f1c193 100644 --- a/Example/SDWebImageSwiftUIDemo/ContentView.swift +++ b/Example/SDWebImageSwiftUIDemo/ContentView.swift @@ -85,6 +85,11 @@ struct ContentView: View { if self.animated { #if os(macOS) || os(iOS) || os(tvOS) AnimatedImage(url: URL(string:url)) + /** + .onViewUpdate { view, context in + view.toolTip = "Mouseover Tip" + } + */ .indicator(SDWebImageActivityIndicator.medium) /** .placeholder(UIImage(systemName: "photo")) diff --git a/README.md b/README.md index 06ecec40..e4c35953 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,9 @@ var body: some View { // Bundle (not Asset Catalog) AnimatedImage(name: "animation1", isAnimating: $isAnimating)) // Animation control binding .maxBufferSize(.max) + .onViewUpdate { view, context in // Advanced native view coordinate + view.toolTip = "Mouseover Tip" + } } } ```