Skip to content

Commit 34360f4

Browse files
authored
Merge pull request #81 from SDWebImage/hack_animated_image_resizable_behavior
Fix AnimatedImage resizable behavior, now `resizable` is required to make it resizable, or it will preserve image pixel size
2 parents 9faad75 + 03b6e5d commit 34360f4

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ var body: some View {
121121
.onSuccess { image, cacheType in
122122
// Success
123123
}
124-
.resizable() // Resizable like SwiftUI.Image
124+
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
125125
.placeholder(Image(systemName: "photo")) // Placeholder Image
126126
// Supports ViewBuilder as well
127127
.placeholder {
@@ -141,7 +141,8 @@ Note: From v0.9.0, `WebImage` supports animated image as well! You can use `.ani
141141

142142
```swift
143143
var body: some View {
144-
WebImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"), isAnimating: $isAnimating)) // Animation Control in 1.0.0 (for 0.x version, use `.animated()` modifier)
144+
WebImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"), isAnimating: $isAnimating)) // Animation Control in 1.0.0, supports dynamic changes
145+
// The initial value of binding should be true (or you can use `.animatedImageClass` context option and pass `SDAnimatedImage`)
145146
.customLoopCount(1) // Custom loop count
146147
.playbackRate(2.0) // Playback speed rate
147148
// In 1.0.0, `WebImage` supports advanced control just like `AnimatedImage`, but without the progressive animation support
@@ -166,11 +167,11 @@ var body: some View {
166167
.onFailure { error in
167168
// Error
168169
}
169-
.resizable() // Actually this is not needed unlike SwiftUI.Image
170+
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
170171
.placeholder(UIImage(systemName: "photo")) // Placeholder Image
171172
.indicator(SDWebImageActivityIndicator.medium) // Activity Indicator
172173
.transition(.fade) // Fade Transition
173-
.scaledToFit() // Attention to call it on AnimatedImage, but not `some View` after View Modifier
174+
.scaledToFit() // Attention to call it on AnimatedImage, but not `some View` after View Modifier (Swift Protocol Extension method is static dispatched)
174175

175176
// Data
176177
AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp")))

SDWebImageSwiftUI/Classes/AnimatedImage.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,15 @@ public struct AnimatedImage : PlatformViewRepresentable {
196196
view.wrapped.sd_setImage(with: imageModel.url, placeholderImage: imageConfiguration.placeholder, options: imageModel.webOptions, context: imageModel.webContext, progress: { (receivedSize, expectedSize, _) in
197197
self.imageHandler.progressBlock?(receivedSize, expectedSize)
198198
}) { (image, error, cacheType, _) in
199-
self.layoutView(view, context: context)
199+
// This is a hack because of Xcode 11.3 bug, the @Published does not trigger another `updateUIView` call
200+
// Here I have to use UIKit API to triger the same effect (the window change implicitly cause re-render)
201+
if let hostingView = AnimatedImage.findHostingView(from: view) {
202+
#if os(macOS)
203+
hostingView.viewDidMoveToWindow()
204+
#else
205+
hostingView.didMoveToWindow()
206+
#endif
207+
}
200208
if let image = image {
201209
self.imageHandler.successBlock?(image, cacheType)
202210
} else {
@@ -314,6 +322,11 @@ public struct AnimatedImage : PlatformViewRepresentable {
314322
view.wrapped.contentMode = contentMode
315323
#endif
316324

325+
// Resizable
326+
if let _ = imageLayout.resizingMode {
327+
view.resizable = true
328+
}
329+
317330
// Animated Image does not support resizing mode and rendering mode
318331
if let image = view.wrapped.image, !image.sd_isAnimated, !image.conforms(to: SDAnimatedImageProtocol.self) {
319332
var image = image
@@ -449,6 +462,17 @@ public struct AnimatedImage : PlatformViewRepresentable {
449462
view.wrapped.playbackRate = 1.0
450463
}
451464
}
465+
466+
private static func findHostingView(from entry: PlatformView) -> PlatformView? {
467+
var superview = entry.superview
468+
while let s = superview {
469+
if NSStringFromClass(type(of: s)).contains("HostingView") {
470+
return s
471+
}
472+
superview = s.superview
473+
}
474+
return nil
475+
}
452476
}
453477

454478
// Layout

SDWebImageSwiftUI/Classes/ImageViewWrapper.swift

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class AnimatedImageViewWrapper : PlatformView {
1717
var wrapped = SDAnimatedImageView()
1818
var interpolationQuality = CGInterpolationQuality.default
1919
var shouldAntialias = false
20+
var resizable = false
2021

2122
override public func draw(_ rect: CGRect) {
2223
#if os(macOS)
@@ -45,15 +46,12 @@ public class AnimatedImageViewWrapper : PlatformView {
4546
#endif
4647

4748
public override var intrinsicContentSize: CGSize {
48-
/// Used to fix SwiftUI layout issue when image view is aspectFit/aspectFill :)
49-
/// The container will measure its own size with 1:1 firstly, then change image view size, which cause image view sizing smaller than expected
50-
/// Instead, the container should firstly return its own size with image view's aspect ratio
51-
let size = wrapped.intrinsicContentSize
52-
if size.width > 0 && size.height > 0 {
53-
let aspectRatio = size.height / size.width
54-
return CGSize(width: 1, height: 1 * aspectRatio)
55-
} else {
49+
/// Match the behavior of SwiftUI.Image, only when image is resizable, use the super implementation to calculate size
50+
if resizable {
5651
return super.intrinsicContentSize
52+
} else {
53+
/// Not resizable, always use image size, like SwiftUI.Image
54+
return wrapped.intrinsicContentSize
5755
}
5856
}
5957

0 commit comments

Comments
 (0)