Skip to content

Commit e50a326

Browse files
authored
Merge pull request #35 from SDWebImage/fix_animated_image_scale_logic
Fix AnimatedImage scale logic to match SwiftUI.Image
2 parents 27e8288 + 25daa2d commit e50a326

File tree

2 files changed

+59
-19
lines changed

2 files changed

+59
-19
lines changed

Example/SDWebImageSwiftUIDemo/ContentView.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ struct ContentView: View {
5151
#if os(macOS)
5252
return NavigationView {
5353
contentView()
54+
.frame(minWidth: 200)
55+
.listStyle(SidebarListStyle())
5456
.contextMenu {
5557
Button(action: { self.reloadCache() }) {
5658
Text("Reload")

SDWebImageSwiftUI/Classes/AnimatedImage.swift

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ final class AnimatedImageCoordinator : ObservableObject {
2828

2929
// Layout Binding Object
3030
final class AnimatedImageLayout : ObservableObject {
31-
@Published var contentMode: ContentMode = .fill
31+
@Published var contentMode: ContentMode?
3232
@Published var aspectRatio: CGFloat?
3333
@Published var capInsets: EdgeInsets = EdgeInsets()
3434
@Published var resizingMode: Image.ResizingMode?
@@ -268,30 +268,64 @@ public struct AnimatedImage : PlatformViewRepresentable {
268268
}
269269

270270
func layoutView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext<AnimatedImage>) {
271-
// AspectRatio
272-
// If `aspectRatio` is `nil`, the resulting view maintains this view's aspect ratio.
273-
let contentMode: ContentMode = imageLayout.aspectRatio == nil ? .fit : .fill
274-
275-
// ContentMode
276-
switch contentMode {
277-
case .fit:
278-
#if os(macOS)
279-
view.wrapped.imageScaling = .scaleProportionallyUpOrDown
280-
#elseif os(iOS) || os(tvOS)
281-
view.wrapped.contentMode = .scaleAspectFit
282-
#elseif os(watchOS)
283-
view.wrapped.setContentMode(.aspectFit)
284-
#endif
285-
case .fill:
271+
// AspectRatio && ContentMode
272+
#if os(macOS)
273+
let contentMode: NSImageScaling
274+
#elseif os(iOS) || os(tvOS)
275+
let contentMode: UIView.ContentMode
276+
#elseif os(watchOS)
277+
let contentMode: SDImageScaleMode
278+
#endif
279+
if let _ = imageLayout.aspectRatio {
280+
// If `aspectRatio` is not `nil`, always scale to fill and SwiftUI will layout the container with custom aspect ratio.
286281
#if os(macOS)
287-
view.wrapped.imageScaling = .scaleAxesIndependently
282+
contentMode = .scaleAxesIndependently
288283
#elseif os(iOS) || os(tvOS)
289-
view.wrapped.contentMode = .scaleToFill
284+
contentMode = .scaleToFill
290285
#elseif os(watchOS)
291-
view.wrapped.setContentMode(.fill)
286+
contentMode = .fill
292287
#endif
288+
} else {
289+
// If `aspectRatio` is `nil`, the resulting view maintains this view's aspect ratio.
290+
switch imageLayout.contentMode {
291+
case .fill:
292+
#if os(macOS)
293+
// Actually, NSImageView have no `.aspectFill` unlike UIImageView, only `CALayerContentsGravity.resizeAspectFill` have the same concept, but it does not work here
294+
// TODO: Need SwiftUI officialy provide a solution
295+
contentMode = .scaleProportionallyUpOrDown
296+
#elseif os(iOS) || os(tvOS)
297+
contentMode = .scaleAspectFill
298+
#elseif os(watchOS)
299+
contentMode = .aspectFill
300+
#endif
301+
case .fit:
302+
#if os(macOS)
303+
contentMode = .scaleProportionallyUpOrDown
304+
#elseif os(iOS) || os(tvOS)
305+
contentMode = .scaleAspectFit
306+
#elseif os(watchOS)
307+
contentMode = .aspectFit
308+
#endif
309+
case .none:
310+
// If `contentMode` is not set at all, using scale to fill as SwiftUI default value
311+
#if os(macOS)
312+
contentMode = .scaleAxesIndependently
313+
#elseif os(iOS) || os(tvOS)
314+
contentMode = .scaleToFill
315+
#elseif os(watchOS)
316+
contentMode = .fill
317+
#endif
318+
}
293319
}
294320

321+
#if os(macOS)
322+
view.wrapped.imageScaling = contentMode
323+
#elseif os(iOS) || os(tvOS)
324+
view.wrapped.contentMode = contentMode
325+
#elseif os(watchOS)
326+
view.wrapped.setContentMode(contentMode)
327+
#endif
328+
295329
// Animated Image does not support resizing mode and rendering mode
296330
if let image = imageModel.image, !image.sd_isAnimated, !image.conforms(to: SDAnimatedImageProtocol.self) {
297331
var image = image
@@ -461,6 +495,10 @@ extension AnimatedImage {
461495
imageLayout.antialiased = isAntialiased
462496
return self
463497
}
498+
}
499+
500+
// Aspect Ratio
501+
extension AnimatedImage {
464502
/// Constrains this view's dimensions to the specified aspect ratio.
465503
/// - Parameters:
466504
/// - aspectRatio: The ratio of width to height to use for the resulting

0 commit comments

Comments
 (0)