From bd635fdc2fcf13a2b75e18806d7878053a62a480 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 28 Oct 2019 17:36:55 +0800 Subject: [PATCH 1/2] Implements the AnimatedImage's aspectRatio method, which match the SwiftUI.Image behavior. Using some trick code, but it works at least --- SDWebImageSwiftUI/Classes/AnimatedImage.swift | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index a8bd1693..9feebe75 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -269,12 +269,11 @@ public struct AnimatedImage : PlatformViewRepresentable { func layoutView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext) { // AspectRatio - if let _ = imageLayout.aspectRatio { - // TODO: Needs layer transform and geometry calculation - } + // If `aspectRatio` is `nil`, the resulting view maintains this view's aspect ratio. + let contentMode: ContentMode = imageLayout.aspectRatio == nil ? .fit : .fill // ContentMode - switch imageLayout.contentMode { + switch contentMode { case .fit: #if os(macOS) view.wrapped.imageScaling = .scaleProportionallyUpOrDown @@ -471,10 +470,18 @@ extension AnimatedImage { /// fill the parent context. /// - Returns: A view that constrains this view's dimensions to /// `aspectRatio`, using `contentMode` as its scaling algorithm. - public func aspectRatio(_ aspectRatio: CGFloat? = nil, contentMode: ContentMode) -> AnimatedImage { + public func aspectRatio(_ aspectRatio: CGFloat? = nil, contentMode: ContentMode) -> some View { + // The `SwifUI.View.aspectRatio(_:contentMode:)` says: + // If `aspectRatio` is `nil`, the resulting view maintains this view's aspect ratio + // But 1: there are no public API to declare what `this view's aspect ratio` is + // So, if we don't override this method, SwiftUI ignore the content mode on actual ImageView + // To workaround, we want to call the default `SwifUI.View.aspectRatio(_:contentMode:)` method + // 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 - return self + return self.modifier(EmptyModifier()).aspectRatio(aspectRatio, contentMode: contentMode) } /// Constrains this view's dimensions to the aspect ratio of the given size. @@ -485,7 +492,7 @@ extension AnimatedImage { /// fill the parent context. /// - Returns: A view that constrains this view's dimensions to /// `aspectRatio`, using `contentMode` as its scaling algorithm. - public func aspectRatio(_ aspectRatio: CGSize, contentMode: ContentMode) -> AnimatedImage { + public func aspectRatio(_ aspectRatio: CGSize, contentMode: ContentMode) -> some View { var ratio: CGFloat? if aspectRatio.width > 0 && aspectRatio.height > 0 { ratio = aspectRatio.width / aspectRatio.height @@ -496,15 +503,15 @@ extension AnimatedImage { /// Scales this view to fit its parent. /// - Returns: A view that scales this view to fit its parent, /// maintaining this view's aspect ratio. - public func scaledToFit() -> AnimatedImage { - self.aspectRatio(nil, contentMode: .fit) + public func scaledToFit() -> some View { + return self.aspectRatio(nil, contentMode: .fit) } /// Scales this view to fill its parent. /// - Returns: A view that scales this view to fit its parent, /// maintaining this view's aspect ratio. - public func scaledToFill() -> AnimatedImage { - self.aspectRatio(nil, contentMode: .fill) + public func scaledToFill() -> some View { + return self.aspectRatio(nil, contentMode: .fill) } } From 07787e04f495e79cabbdb47fd7c53abbce74a6fe Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Mon, 28 Oct 2019 18:31:52 +0800 Subject: [PATCH 2/2] Throw a exception when user contains mistake to call aspectRatio with non-positive values. This is exist behavior of SwiftUI's Image (But the exception is different) --- SDWebImageSwiftUI/Classes/AnimatedImage.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index 9feebe75..3ba46bf4 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -496,6 +496,8 @@ extension AnimatedImage { var ratio: CGFloat? if aspectRatio.width > 0 && aspectRatio.height > 0 { ratio = aspectRatio.width / aspectRatio.height + } else { + NSException(name: .invalidArgumentException, reason: "\(type(of: self)).\(#function) should be called with positive aspectRatio", userInfo: nil).raise() } return self.aspectRatio(ratio, contentMode: contentMode) }