From 3340ea4ed46b10e3a15b95ea10532e4ad2ec93b0 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 27 Jun 2024 17:53:07 +0800 Subject: [PATCH] Fix the compatibility with UIView transition Actually this is not the good design, but at least a workaround --- SDWebImageSwiftUI/Classes/AnimatedImage.swift | 25 ++++++++++++++----- .../Classes/ImageViewWrapper.swift | 20 ++++++++++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index 83d0b2c..193c9eb 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -275,9 +275,8 @@ public struct AnimatedImage : PlatformViewRepresentable { self.imageModel.placeholderView?.isHidden = false self.imageHandler.failureBlock?(error ?? NSError()) } - // Finished loading - configureView(view, context: context) - layoutView(view, context: context) + // Finished loading, async + finishUpdateView(view, context: context, image: image) } } @@ -310,6 +309,8 @@ public struct AnimatedImage : PlatformViewRepresentable { #endif context.coordinator.imageLoading.imageName = name view.wrapped.image = image + // Finished loading, sync + finishUpdateView(view, context: context, image: image) } private func updateViewForData(_ data: Data?, view: AnimatedImageViewWrapper, context: Context) { @@ -323,6 +324,8 @@ public struct AnimatedImage : PlatformViewRepresentable { } context.coordinator.imageLoading.imageData = data view.wrapped.image = image + // Finished loading, sync + finishUpdateView(view, context: context, image: image) } private func updateViewForURL(_ url: URL?, view: AnimatedImageViewWrapper, context: Context) { @@ -347,6 +350,8 @@ public struct AnimatedImage : PlatformViewRepresentable { setupIndicator(view, context: context) loadImage(view, context: context) } + // Finished loading, sync + finishUpdateView(view, context: context, image: view.wrapped.image) } func updateView(_ view: AnimatedImageViewWrapper, context: Context) { @@ -364,9 +369,6 @@ public struct AnimatedImage : PlatformViewRepresentable { break // impossible } - // Finished loading - configureView(view, context: context) - layoutView(view, context: context) if let viewUpdateBlock = imageHandler.viewUpdateBlock { viewUpdateBlock(view.wrapped, context) } @@ -384,6 +386,17 @@ public struct AnimatedImage : PlatformViewRepresentable { } } + func finishUpdateView(_ view: AnimatedImageViewWrapper, context: Context, image: PlatformImage?) { + // Finished loading + if let imageSize = image?.size { + view.imageSize = imageSize + } else { + view.imageSize = nil + } + configureView(view, context: context) + layoutView(view, context: context) + } + func layoutView(_ view: AnimatedImageViewWrapper, context: Context) { // AspectRatio && ContentMode #if os(macOS) diff --git a/SDWebImageSwiftUI/Classes/ImageViewWrapper.swift b/SDWebImageSwiftUI/Classes/ImageViewWrapper.swift index cfe81ba..e019881 100644 --- a/SDWebImageSwiftUI/Classes/ImageViewWrapper.swift +++ b/SDWebImageSwiftUI/Classes/ImageViewWrapper.swift @@ -20,6 +20,7 @@ public class AnimatedImageViewWrapper : PlatformView { var interpolationQuality = CGInterpolationQuality.default var shouldAntialias = false var resizingMode: Image.ResizingMode? + var imageSize: CGSize? public override func draw(_ rect: CGRect) { #if os(macOS) @@ -49,20 +50,27 @@ public class AnimatedImageViewWrapper : PlatformView { public override var intrinsicContentSize: CGSize { /// Match the behavior of SwiftUI.Image, only when image is resizable, use the super implementation to calculate size - let imageSize = wrapped.intrinsicContentSize + var contentSize = wrapped.intrinsicContentSize + /// Sometimes, like during the transaction, the wrapped.image == nil, which cause contentSize invalid + /// Use image size as backup + /// TODO: This mixed use of UIKit/SwiftUI animation will cause visial issue because the intrinsicContentSize during animation may be changed + if let imageSize = imageSize { + if contentSize != imageSize { + contentSize = imageSize + } + } if let _ = resizingMode { /// Keep aspect ratio - let noIntrinsicMetric = AnimatedImageViewWrapper.noIntrinsicMetric - if (imageSize.width > 0 && imageSize.height > 0) { - let ratio = imageSize.width / imageSize.height + if contentSize.width > 0 && contentSize.height > 0 { + let ratio = contentSize.width / contentSize.height let size = CGSize(width: ratio, height: 1) return size } else { - return CGSize(width: noIntrinsicMetric, height: noIntrinsicMetric) + return contentSize } } else { /// Not resizable, always use image size, like SwiftUI.Image - return imageSize + return contentSize } }