Merge pull request #326 from SDWebImage/bugfix/transition_animatedImage
Fix the transition visual jump between placeholderImage and final image for AnimatedImage
This commit is contained in:
commit
fc52658f03
|
@ -276,7 +276,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
|
||||||
self.imageHandler.failureBlock?(error ?? NSError())
|
self.imageHandler.failureBlock?(error ?? NSError())
|
||||||
}
|
}
|
||||||
// Finished loading, async
|
// Finished loading, async
|
||||||
finishUpdateView(view, context: context, image: image)
|
finishUpdateView(view, context: context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +364,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finished loading, sync
|
// Finished loading, sync
|
||||||
finishUpdateView(view, context: context, image: view.wrapped.image)
|
finishUpdateView(view, context: context)
|
||||||
|
|
||||||
if let viewUpdateBlock = imageHandler.viewUpdateBlock {
|
if let viewUpdateBlock = imageHandler.viewUpdateBlock {
|
||||||
viewUpdateBlock(view.wrapped, context)
|
viewUpdateBlock(view.wrapped, context)
|
||||||
|
@ -383,13 +383,8 @@ public struct AnimatedImage : PlatformViewRepresentable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func finishUpdateView(_ view: AnimatedImageViewWrapper, context: Context, image: PlatformImage?) {
|
func finishUpdateView(_ view: AnimatedImageViewWrapper, context: Context) {
|
||||||
// Finished loading
|
// Finished loading
|
||||||
if let imageSize = image?.size {
|
|
||||||
view.imageSize = imageSize
|
|
||||||
} else {
|
|
||||||
view.imageSize = nil
|
|
||||||
}
|
|
||||||
configureView(view, context: context)
|
configureView(view, context: context)
|
||||||
layoutView(view, context: context)
|
layoutView(view, context: context)
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ public final class ImageManager : ObservableObject {
|
||||||
weak var currentOperation: SDWebImageOperation? = nil
|
weak var currentOperation: SDWebImageOperation? = nil
|
||||||
|
|
||||||
var currentURL: URL?
|
var currentURL: URL?
|
||||||
|
var transaction = Transaction()
|
||||||
var successBlock: ((PlatformImage, Data?, SDImageCacheType) -> Void)?
|
var successBlock: ((PlatformImage, Data?, SDImageCacheType) -> Void)?
|
||||||
var failureBlock: ((Error) -> Void)?
|
var failureBlock: ((Error) -> Void)?
|
||||||
var progressBlock: ((Int, Int) -> Void)?
|
var progressBlock: ((Int, Int) -> Void)?
|
||||||
|
@ -106,6 +107,7 @@ public final class ImageManager : ObservableObject {
|
||||||
// So previous View struct call `onDisappear` and cancel the currentOperation
|
// So previous View struct call `onDisappear` and cancel the currentOperation
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
withTransaction(transaction) {
|
||||||
self.image = image
|
self.image = image
|
||||||
self.error = error
|
self.error = error
|
||||||
self.isIncremental = !finished
|
self.isIncremental = !finished
|
||||||
|
@ -122,6 +124,7 @@ public final class ImageManager : ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Cancel the current url loading
|
/// Cancel the current url loading
|
||||||
public func cancel() {
|
public func cancel() {
|
||||||
|
|
|
@ -16,11 +16,15 @@ import SwiftUI
|
||||||
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
|
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||||
public class AnimatedImageViewWrapper : PlatformView {
|
public class AnimatedImageViewWrapper : PlatformView {
|
||||||
/// The wrapped actual image view, using SDWebImage's aniamted image view
|
/// The wrapped actual image view, using SDWebImage's aniamted image view
|
||||||
public var wrapped = SDAnimatedImageView()
|
@objc dynamic public var wrapped = SDAnimatedImageView()
|
||||||
|
var observation: NSKeyValueObservation?
|
||||||
var interpolationQuality = CGInterpolationQuality.default
|
var interpolationQuality = CGInterpolationQuality.default
|
||||||
var shouldAntialias = false
|
var shouldAntialias = false
|
||||||
var resizingMode: Image.ResizingMode?
|
var resizingMode: Image.ResizingMode?
|
||||||
var imageSize: CGSize?
|
|
||||||
|
deinit {
|
||||||
|
observation?.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
public override func draw(_ rect: CGRect) {
|
public override func draw(_ rect: CGRect) {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
|
@ -50,15 +54,7 @@ public class AnimatedImageViewWrapper : PlatformView {
|
||||||
|
|
||||||
public override var intrinsicContentSize: CGSize {
|
public override var intrinsicContentSize: CGSize {
|
||||||
/// Match the behavior of SwiftUI.Image, only when image is resizable, use the super implementation to calculate size
|
/// Match the behavior of SwiftUI.Image, only when image is resizable, use the super implementation to calculate size
|
||||||
var contentSize = wrapped.intrinsicContentSize
|
let 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 {
|
if let _ = resizingMode {
|
||||||
/// Keep aspect ratio
|
/// Keep aspect ratio
|
||||||
if contentSize.width > 0 && contentSize.height > 0 {
|
if contentSize.width > 0 && contentSize.height > 0 {
|
||||||
|
@ -77,11 +73,17 @@ public class AnimatedImageViewWrapper : PlatformView {
|
||||||
public override init(frame frameRect: CGRect) {
|
public override init(frame frameRect: CGRect) {
|
||||||
super.init(frame: frameRect)
|
super.init(frame: frameRect)
|
||||||
addSubview(wrapped)
|
addSubview(wrapped)
|
||||||
|
observation = observe(\.wrapped.image, options: [.new]) { _, _ in
|
||||||
|
self.invalidateIntrinsicContentSize()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public required init?(coder: NSCoder) {
|
public required init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
addSubview(wrapped)
|
addSubview(wrapped)
|
||||||
|
observation = observe(\.wrapped.image, options: [.new]) { _, _ in
|
||||||
|
self.invalidateIntrinsicContentSize()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,8 +81,6 @@ final class WebImageConfiguration: ObservableObject {
|
||||||
/// A Image View type to load image from url. Supports static/animated image format.
|
/// A Image View type to load image from url. Supports static/animated image format.
|
||||||
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
|
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||||
public struct WebImage<Content> : View where Content: View {
|
public struct WebImage<Content> : View where Content: View {
|
||||||
var transaction: Transaction
|
|
||||||
|
|
||||||
var configurations: [(Image) -> Image] = []
|
var configurations: [(Image) -> Image] = []
|
||||||
|
|
||||||
var content: (WebImagePhase) -> Content
|
var content: (WebImagePhase) -> Content
|
||||||
|
@ -146,10 +144,10 @@ public struct WebImage<Content> : View where Content: View {
|
||||||
imageModel.context = context
|
imageModel.context = context
|
||||||
_imageModel = ObservedObject(wrappedValue: imageModel)
|
_imageModel = ObservedObject(wrappedValue: imageModel)
|
||||||
let imageManager = ImageManager()
|
let imageManager = ImageManager()
|
||||||
|
imageManager.transaction = transaction
|
||||||
_imageManager = StateObject(wrappedValue: imageManager)
|
_imageManager = StateObject(wrappedValue: imageManager)
|
||||||
_indicatorStatus = ObservedObject(wrappedValue: imageManager.indicatorStatus)
|
_indicatorStatus = ObservedObject(wrappedValue: imageManager.indicatorStatus)
|
||||||
|
|
||||||
self.transaction = transaction
|
|
||||||
self.content = { phase in
|
self.content = { phase in
|
||||||
content(phase)
|
content(phase)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue