Skip to content

Commit fc52658

Browse files
authored
Merge pull request #326 from SDWebImage/bugfix/transition_animatedImage
Fix the transition visual jump between placeholderImage and final image for AnimatedImage
2 parents 02b2579 + d68c13a commit fc52658

File tree

4 files changed

+32
-34
lines changed

4 files changed

+32
-34
lines changed

SDWebImageSwiftUI/Classes/AnimatedImage.swift

+3-8
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
276276
self.imageHandler.failureBlock?(error ?? NSError())
277277
}
278278
// Finished loading, async
279-
finishUpdateView(view, context: context, image: image)
279+
finishUpdateView(view, context: context)
280280
}
281281
}
282282

@@ -364,7 +364,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
364364
}
365365

366366
// Finished loading, sync
367-
finishUpdateView(view, context: context, image: view.wrapped.image)
367+
finishUpdateView(view, context: context)
368368

369369
if let viewUpdateBlock = imageHandler.viewUpdateBlock {
370370
viewUpdateBlock(view.wrapped, context)
@@ -383,13 +383,8 @@ public struct AnimatedImage : PlatformViewRepresentable {
383383
}
384384
}
385385

386-
func finishUpdateView(_ view: AnimatedImageViewWrapper, context: Context, image: PlatformImage?) {
386+
func finishUpdateView(_ view: AnimatedImageViewWrapper, context: Context) {
387387
// Finished loading
388-
if let imageSize = image?.size {
389-
view.imageSize = imageSize
390-
} else {
391-
view.imageSize = nil
392-
}
393388
configureView(view, context: context)
394389
layoutView(view, context: context)
395390
}

SDWebImageSwiftUI/Classes/ImageManager.swift

+15-12
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public final class ImageManager : ObservableObject {
6060
weak var currentOperation: SDWebImageOperation? = nil
6161

6262
var currentURL: URL?
63+
var transaction = Transaction()
6364
var successBlock: ((PlatformImage, Data?, SDImageCacheType) -> Void)?
6465
var failureBlock: ((Error) -> Void)?
6566
var progressBlock: ((Int, Int) -> Void)?
@@ -106,18 +107,20 @@ public final class ImageManager : ObservableObject {
106107
// So previous View struct call `onDisappear` and cancel the currentOperation
107108
return
108109
}
109-
self.image = image
110-
self.error = error
111-
self.isIncremental = !finished
112-
if finished {
113-
self.imageData = data
114-
self.cacheType = cacheType
115-
self.indicatorStatus.isLoading = false
116-
self.indicatorStatus.progress = 1
117-
if let image = image {
118-
self.successBlock?(image, data, cacheType)
119-
} else {
120-
self.failureBlock?(error ?? NSError())
110+
withTransaction(transaction) {
111+
self.image = image
112+
self.error = error
113+
self.isIncremental = !finished
114+
if finished {
115+
self.imageData = data
116+
self.cacheType = cacheType
117+
self.indicatorStatus.isLoading = false
118+
self.indicatorStatus.progress = 1
119+
if let image = image {
120+
self.successBlock?(image, data, cacheType)
121+
} else {
122+
self.failureBlock?(error ?? NSError())
123+
}
121124
}
122125
}
123126
}

SDWebImageSwiftUI/Classes/ImageViewWrapper.swift

+13-11
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@ import SwiftUI
1616
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
1717
public class AnimatedImageViewWrapper : PlatformView {
1818
/// The wrapped actual image view, using SDWebImage's aniamted image view
19-
public var wrapped = SDAnimatedImageView()
19+
@objc dynamic public var wrapped = SDAnimatedImageView()
20+
var observation: NSKeyValueObservation?
2021
var interpolationQuality = CGInterpolationQuality.default
2122
var shouldAntialias = false
2223
var resizingMode: Image.ResizingMode?
23-
var imageSize: CGSize?
24+
25+
deinit {
26+
observation?.invalidate()
27+
}
2428

2529
public override func draw(_ rect: CGRect) {
2630
#if os(macOS)
@@ -50,15 +54,7 @@ public class AnimatedImageViewWrapper : PlatformView {
5054

5155
public override var intrinsicContentSize: CGSize {
5256
/// Match the behavior of SwiftUI.Image, only when image is resizable, use the super implementation to calculate size
53-
var contentSize = wrapped.intrinsicContentSize
54-
/// Sometimes, like during the transaction, the wrapped.image == nil, which cause contentSize invalid
55-
/// Use image size as backup
56-
/// TODO: This mixed use of UIKit/SwiftUI animation will cause visial issue because the intrinsicContentSize during animation may be changed
57-
if let imageSize = imageSize {
58-
if contentSize != imageSize {
59-
contentSize = imageSize
60-
}
61-
}
57+
let contentSize = wrapped.intrinsicContentSize
6258
if let _ = resizingMode {
6359
/// Keep aspect ratio
6460
if contentSize.width > 0 && contentSize.height > 0 {
@@ -77,11 +73,17 @@ public class AnimatedImageViewWrapper : PlatformView {
7773
public override init(frame frameRect: CGRect) {
7874
super.init(frame: frameRect)
7975
addSubview(wrapped)
76+
observation = observe(\.wrapped.image, options: [.new]) { _, _ in
77+
self.invalidateIntrinsicContentSize()
78+
}
8079
}
8180

8281
public required init?(coder: NSCoder) {
8382
super.init(coder: coder)
8483
addSubview(wrapped)
84+
observation = observe(\.wrapped.image, options: [.new]) { _, _ in
85+
self.invalidateIntrinsicContentSize()
86+
}
8587
}
8688
}
8789

SDWebImageSwiftUI/Classes/WebImage.swift

+1-3
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ final class WebImageConfiguration: ObservableObject {
8181
/// A Image View type to load image from url. Supports static/animated image format.
8282
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
8383
public struct WebImage<Content> : View where Content: View {
84-
var transaction: Transaction
85-
8684
var configurations: [(Image) -> Image] = []
8785

8886
var content: (WebImagePhase) -> Content
@@ -146,10 +144,10 @@ public struct WebImage<Content> : View where Content: View {
146144
imageModel.context = context
147145
_imageModel = ObservedObject(wrappedValue: imageModel)
148146
let imageManager = ImageManager()
147+
imageManager.transaction = transaction
149148
_imageManager = StateObject(wrappedValue: imageManager)
150149
_indicatorStatus = ObservedObject(wrappedValue: imageManager.indicatorStatus)
151150

152-
self.transaction = transaction
153151
self.content = { phase in
154152
content(phase)
155153
}

0 commit comments

Comments
 (0)