Skip to content

Fix AnimatedImage scale logic to match SwiftUI.Image #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Example/SDWebImageSwiftUIDemo/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ struct ContentView: View {
#if os(macOS)
return NavigationView {
contentView()
.frame(minWidth: 200)
.listStyle(SidebarListStyle())
.contextMenu {
Button(action: { self.reloadCache() }) {
Text("Reload")
Expand Down
76 changes: 57 additions & 19 deletions SDWebImageSwiftUI/Classes/AnimatedImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ final class AnimatedImageCoordinator : ObservableObject {

// Layout Binding Object
final class AnimatedImageLayout : ObservableObject {
@Published var contentMode: ContentMode = .fill
@Published var contentMode: ContentMode?
@Published var aspectRatio: CGFloat?
@Published var capInsets: EdgeInsets = EdgeInsets()
@Published var resizingMode: Image.ResizingMode?
Expand Down Expand Up @@ -268,30 +268,64 @@ public struct AnimatedImage : PlatformViewRepresentable {
}

func layoutView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext<AnimatedImage>) {
// AspectRatio
// If `aspectRatio` is `nil`, the resulting view maintains this view's aspect ratio.
let contentMode: ContentMode = imageLayout.aspectRatio == nil ? .fit : .fill

// ContentMode
switch contentMode {
case .fit:
#if os(macOS)
view.wrapped.imageScaling = .scaleProportionallyUpOrDown
#elseif os(iOS) || os(tvOS)
view.wrapped.contentMode = .scaleAspectFit
#elseif os(watchOS)
view.wrapped.setContentMode(.aspectFit)
#endif
case .fill:
// AspectRatio && ContentMode
#if os(macOS)
let contentMode: NSImageScaling
#elseif os(iOS) || os(tvOS)
let contentMode: UIView.ContentMode
#elseif os(watchOS)
let contentMode: SDImageScaleMode
#endif
if let _ = imageLayout.aspectRatio {
// If `aspectRatio` is not `nil`, always scale to fill and SwiftUI will layout the container with custom aspect ratio.
#if os(macOS)
view.wrapped.imageScaling = .scaleAxesIndependently
contentMode = .scaleAxesIndependently
#elseif os(iOS) || os(tvOS)
view.wrapped.contentMode = .scaleToFill
contentMode = .scaleToFill
#elseif os(watchOS)
view.wrapped.setContentMode(.fill)
contentMode = .fill
#endif
} else {
// If `aspectRatio` is `nil`, the resulting view maintains this view's aspect ratio.
switch imageLayout.contentMode {
case .fill:
#if os(macOS)
// Actually, NSImageView have no `.aspectFill` unlike UIImageView, only `CALayerContentsGravity.resizeAspectFill` have the same concept, but it does not work here
// TODO: Need SwiftUI officialy provide a solution
contentMode = .scaleProportionallyUpOrDown
#elseif os(iOS) || os(tvOS)
contentMode = .scaleAspectFill
#elseif os(watchOS)
contentMode = .aspectFill
#endif
case .fit:
#if os(macOS)
contentMode = .scaleProportionallyUpOrDown
#elseif os(iOS) || os(tvOS)
contentMode = .scaleAspectFit
#elseif os(watchOS)
contentMode = .aspectFit
#endif
case .none:
// If `contentMode` is not set at all, using scale to fill as SwiftUI default value
#if os(macOS)
contentMode = .scaleAxesIndependently
#elseif os(iOS) || os(tvOS)
contentMode = .scaleToFill
#elseif os(watchOS)
contentMode = .fill
#endif
}
}

#if os(macOS)
view.wrapped.imageScaling = contentMode
#elseif os(iOS) || os(tvOS)
view.wrapped.contentMode = contentMode
#elseif os(watchOS)
view.wrapped.setContentMode(contentMode)
#endif

// Animated Image does not support resizing mode and rendering mode
if let image = imageModel.image, !image.sd_isAnimated, !image.conforms(to: SDAnimatedImageProtocol.self) {
var image = image
Expand Down Expand Up @@ -461,6 +495,10 @@ extension AnimatedImage {
imageLayout.antialiased = isAntialiased
return self
}
}

// Aspect Ratio
extension AnimatedImage {
/// Constrains this view's dimensions to the specified aspect ratio.
/// - Parameters:
/// - aspectRatio: The ratio of width to height to use for the resulting
Expand Down