Skip to content
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

Fix the transition visual jump between placeholderImage and final image for AnimatedImage #326

Merged
merged 2 commits into from
Jul 1, 2024
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
11 changes: 3 additions & 8 deletions SDWebImageSwiftUI/Classes/AnimatedImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
self.imageHandler.failureBlock?(error ?? NSError())
}
// Finished loading, async
finishUpdateView(view, context: context, image: image)
finishUpdateView(view, context: context)
}
}

Expand Down Expand Up @@ -364,7 +364,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
}

// Finished loading, sync
finishUpdateView(view, context: context, image: view.wrapped.image)
finishUpdateView(view, context: context)

if let viewUpdateBlock = imageHandler.viewUpdateBlock {
viewUpdateBlock(view.wrapped, context)
Expand All @@ -383,13 +383,8 @@ public struct AnimatedImage : PlatformViewRepresentable {
}
}

func finishUpdateView(_ view: AnimatedImageViewWrapper, context: Context, image: PlatformImage?) {
func finishUpdateView(_ view: AnimatedImageViewWrapper, context: Context) {
// Finished loading
if let imageSize = image?.size {
view.imageSize = imageSize
} else {
view.imageSize = nil
}
configureView(view, context: context)
layoutView(view, context: context)
}
Expand Down
27 changes: 15 additions & 12 deletions SDWebImageSwiftUI/Classes/ImageManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public final class ImageManager : ObservableObject {
weak var currentOperation: SDWebImageOperation? = nil

var currentURL: URL?
var transaction = Transaction()
var successBlock: ((PlatformImage, Data?, SDImageCacheType) -> Void)?
var failureBlock: ((Error) -> Void)?
var progressBlock: ((Int, Int) -> Void)?
Expand Down Expand Up @@ -106,18 +107,20 @@ public final class ImageManager : ObservableObject {
// So previous View struct call `onDisappear` and cancel the currentOperation
return
}
self.image = image
self.error = error
self.isIncremental = !finished
if finished {
self.imageData = data
self.cacheType = cacheType
self.indicatorStatus.isLoading = false
self.indicatorStatus.progress = 1
if let image = image {
self.successBlock?(image, data, cacheType)
} else {
self.failureBlock?(error ?? NSError())
withTransaction(transaction) {
self.image = image
self.error = error
self.isIncremental = !finished
if finished {
self.imageData = data
self.cacheType = cacheType
self.indicatorStatus.isLoading = false
self.indicatorStatus.progress = 1
if let image = image {
self.successBlock?(image, data, cacheType)
} else {
self.failureBlock?(error ?? NSError())
}
}
}
}
Expand Down
24 changes: 13 additions & 11 deletions SDWebImageSwiftUI/Classes/ImageViewWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ import SwiftUI
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
public class AnimatedImageViewWrapper : PlatformView {
/// 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 shouldAntialias = false
var resizingMode: Image.ResizingMode?
var imageSize: CGSize?

deinit {
observation?.invalidate()
}

public override func draw(_ rect: CGRect) {
#if os(macOS)
Expand Down Expand Up @@ -50,15 +54,7 @@ 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
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
}
}
let contentSize = wrapped.intrinsicContentSize
if let _ = resizingMode {
/// Keep aspect ratio
if contentSize.width > 0 && contentSize.height > 0 {
Expand All @@ -77,11 +73,17 @@ public class AnimatedImageViewWrapper : PlatformView {
public override init(frame frameRect: CGRect) {
super.init(frame: frameRect)
addSubview(wrapped)
observation = observe(\.wrapped.image, options: [.new]) { _, _ in
self.invalidateIntrinsicContentSize()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have to use KVO to get notified when subview's content changes...No better idea

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use _, _ instead

}
}

public required init?(coder: NSCoder) {
super.init(coder: coder)
addSubview(wrapped)
observation = observe(\.wrapped.image, options: [.new]) { _, _ in
self.invalidateIntrinsicContentSize()
}
}
}

Expand Down
4 changes: 1 addition & 3 deletions SDWebImageSwiftUI/Classes/WebImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ final class WebImageConfiguration: ObservableObject {
/// 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, *)
public struct WebImage<Content> : View where Content: View {
var transaction: Transaction

var configurations: [(Image) -> Image] = []

var content: (WebImagePhase) -> Content
Expand Down Expand Up @@ -146,10 +144,10 @@ public struct WebImage<Content> : View where Content: View {
imageModel.context = context
_imageModel = ObservedObject(wrappedValue: imageModel)
let imageManager = ImageManager()
imageManager.transaction = transaction
_imageManager = StateObject(wrappedValue: imageManager)
_indicatorStatus = ObservedObject(wrappedValue: imageManager.indicatorStatus)

self.transaction = transaction
self.content = { phase in
content(phase)
}
Expand Down
Loading