Skip to content

Commit 84e254c

Browse files
committed
Use the new way for AnimatedImageViewWrapper, fix the transition visual jump between placeholderImage and final image
1 parent 02b2579 commit 84e254c

File tree

2 files changed

+52
-87
lines changed

2 files changed

+52
-87
lines changed

SDWebImageSwiftUI/Classes/AnimatedImage.swift

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -218,26 +218,29 @@ public struct AnimatedImage : PlatformViewRepresentable {
218218
updateView(uiView, context: context)
219219
}
220220

221+
// public func sizeThatFits(_ proposal: ProposedViewSize, uiView: AnimatedImageViewWrapper, context: Context) -> CGSize? {}
222+
// func _overrideSizeThatFits(_ size: inout CGSize, in proposedSize: _ProposedSize, uiView: UIViewType) {}
223+
221224
public static func dismantleUIView(_ uiView: AnimatedImageViewWrapper, coordinator: Coordinator) {
222225
dismantleView(uiView, coordinator: coordinator)
223226
}
224227
#endif
225228

226229
func setupIndicator(_ view: AnimatedImageViewWrapper, context: Context) {
227-
view.wrapped.sd_imageIndicator = imageConfiguration.indicator
228-
view.wrapped.sd_imageTransition = imageConfiguration.transition
230+
view.sd_imageIndicator = imageConfiguration.indicator
231+
view.sd_imageTransition = imageConfiguration.transition
229232
if let placeholderView = imageModel.placeholderView {
230233
placeholderView.removeFromSuperview()
231234
placeholderView.isHidden = true
232235
// Placeholder View should below the Indicator View
233236
if let indicatorView = imageConfiguration.indicator?.indicatorView {
234237
#if os(macOS)
235-
view.wrapped.addSubview(placeholderView, positioned: .below, relativeTo: indicatorView)
238+
view.addSubview(placeholderView, positioned: .below, relativeTo: indicatorView)
236239
#else
237-
view.wrapped.insertSubview(placeholderView, belowSubview: indicatorView)
240+
view.insertSubview(placeholderView, belowSubview: indicatorView)
238241
#endif
239242
} else {
240-
view.wrapped.addSubview(placeholderView)
243+
view.addSubview(placeholderView)
241244
}
242245
placeholderView.bindFrameToSuperviewBounds()
243246
}
@@ -253,7 +256,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
253256
}
254257
var webContext = imageModel.webContext ?? [:]
255258
webContext[.animatedImageClass] = SDAnimatedImage.self
256-
view.wrapped.sd_internalSetImage(with: imageModel.url, placeholderImage: imageModel.placeholderImage, options: webOptions, context: webContext, setImageBlock: nil, progress: { (receivedSize, expectedSize, _) in
259+
view.sd_internalSetImage(with: imageModel.url, placeholderImage: imageModel.placeholderImage, options: webOptions, context: webContext, setImageBlock: nil, progress: { (receivedSize, expectedSize, _) in
257260
let progress: Double
258261
if (expectedSize > 0) {
259262
progress = Double(receivedSize) / Double(expectedSize)
@@ -276,14 +279,14 @@ public struct AnimatedImage : PlatformViewRepresentable {
276279
self.imageHandler.failureBlock?(error ?? NSError())
277280
}
278281
// Finished loading, async
279-
finishUpdateView(view, context: context, image: image)
282+
finishUpdateView(view, context: context)
280283
}
281284
}
282285

283286
func makeView(context: Context) -> AnimatedImageViewWrapper {
284287
let view = AnimatedImageViewWrapper()
285288
if let viewCreateBlock = imageHandler.viewCreateBlock {
286-
viewCreateBlock(view.wrapped, context)
289+
viewCreateBlock(view, context)
287290
}
288291
return view
289292
}
@@ -308,7 +311,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
308311
}
309312
#endif
310313
context.coordinator.imageLoading.imageName = name
311-
view.wrapped.image = image
314+
view.image = image
312315
}
313316

314317
private func updateViewForData(_ data: Data?, view: AnimatedImageViewWrapper, context: Context) {
@@ -321,7 +324,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
321324
image = PlatformImage.sd_image(with: data, scale: imageModel.scale)
322325
}
323326
context.coordinator.imageLoading.imageData = data
324-
view.wrapped.image = image
327+
view.image = image
325328
}
326329

327330
private func updateViewForURL(_ url: URL?, view: AnimatedImageViewWrapper, context: Context) {
@@ -337,7 +340,7 @@ public struct AnimatedImage : PlatformViewRepresentable {
337340
shouldLoad = false
338341
} else if let image = context.coordinator.imageLoading.image {
339342
shouldLoad = false
340-
view.wrapped.image = image
343+
view.image = image
341344
} else {
342345
shouldLoad = true
343346
}
@@ -364,32 +367,27 @@ public struct AnimatedImage : PlatformViewRepresentable {
364367
}
365368

366369
// Finished loading, sync
367-
finishUpdateView(view, context: context, image: view.wrapped.image)
370+
finishUpdateView(view, context: context)
368371

369372
if let viewUpdateBlock = imageHandler.viewUpdateBlock {
370-
viewUpdateBlock(view.wrapped, context)
373+
viewUpdateBlock(view, context)
371374
}
372375
}
373376

374377
static func dismantleView(_ view: AnimatedImageViewWrapper, coordinator: Coordinator) {
375-
view.wrapped.sd_cancelCurrentImageLoad()
378+
view.sd_cancelCurrentImageLoad()
376379
#if os(macOS)
377-
view.wrapped.animates = false
380+
view.animates = false
378381
#else
379-
view.wrapped.stopAnimating()
382+
view.stopAnimating()
380383
#endif
381384
if let viewDestroyBlock = viewDestroyBlock {
382-
viewDestroyBlock(view.wrapped, coordinator)
385+
viewDestroyBlock(view, coordinator)
383386
}
384387
}
385388

386-
func finishUpdateView(_ view: AnimatedImageViewWrapper, context: Context, image: PlatformImage?) {
389+
func finishUpdateView(_ view: AnimatedImageViewWrapper, context: Context) {
387390
// Finished loading
388-
if let imageSize = image?.size {
389-
view.imageSize = imageSize
390-
} else {
391-
view.imageSize = nil
392-
}
393391
configureView(view, context: context)
394392
layoutView(view, context: context)
395393
}
@@ -436,16 +434,16 @@ public struct AnimatedImage : PlatformViewRepresentable {
436434
}
437435

438436
#if os(macOS)
439-
view.wrapped.imageScaling = contentMode
437+
view.imageScaling = contentMode
440438
#else
441-
view.wrapped.contentMode = contentMode
439+
view.contentMode = contentMode
442440
#endif
443441

444442
// Resizable
445443
view.resizingMode = imageLayout.resizingMode
446444

447445
// Animated Image does not support resizing mode and rendering mode
448-
if let image = view.wrapped.image {
446+
if let image = view.image {
449447
var image = image
450448
// ResizingMode
451449
if let resizingMode = imageLayout.resizingMode, imageLayout.capInsets != EdgeInsets() {
@@ -462,15 +460,15 @@ public struct AnimatedImage : PlatformViewRepresentable {
462460
#else
463461
image = image.resizableImage(withCapInsets: capInsets, resizingMode: .stretch)
464462
#endif
465-
view.wrapped.image = image
463+
view.image = image
466464
case .tile:
467465
#if os(macOS)
468466
image.resizingMode = .tile
469467
image.capInsets = capInsets
470468
#else
471469
image = image.resizableImage(withCapInsets: capInsets, resizingMode: .tile)
472470
#endif
473-
view.wrapped.image = image
471+
view.image = image
474472
@unknown default:
475473
// Future cases, not implements
476474
break
@@ -486,14 +484,14 @@ public struct AnimatedImage : PlatformViewRepresentable {
486484
#else
487485
image = image.withRenderingMode(.alwaysTemplate)
488486
#endif
489-
view.wrapped.image = image
487+
view.image = image
490488
case .original:
491489
#if os(macOS)
492490
image.isTemplate = false
493491
#else
494492
image = image.withRenderingMode(.alwaysOriginal)
495493
#endif
496-
view.wrapped.image = image
494+
view.image = image
497495
@unknown default:
498496
// Future cases, not implements
499497
break
@@ -529,74 +527,74 @@ public struct AnimatedImage : PlatformViewRepresentable {
529527
func configureView(_ view: AnimatedImageViewWrapper, context: Context) {
530528
// IncrementalLoad
531529
if let incrementalLoad = imageConfiguration.incrementalLoad {
532-
view.wrapped.shouldIncrementalLoad = incrementalLoad
530+
view.shouldIncrementalLoad = incrementalLoad
533531
} else {
534-
view.wrapped.shouldIncrementalLoad = true
532+
view.shouldIncrementalLoad = true
535533
}
536534

537535
// MaxBufferSize
538536
if let maxBufferSize = imageConfiguration.maxBufferSize {
539-
view.wrapped.maxBufferSize = maxBufferSize
537+
view.maxBufferSize = maxBufferSize
540538
} else {
541539
// automatically
542-
view.wrapped.maxBufferSize = 0
540+
view.maxBufferSize = 0
543541
}
544542

545543
// CustomLoopCount
546544
if let customLoopCount = imageConfiguration.customLoopCount {
547-
view.wrapped.shouldCustomLoopCount = true
548-
view.wrapped.animationRepeatCount = Int(customLoopCount)
545+
view.shouldCustomLoopCount = true
546+
view.animationRepeatCount = Int(customLoopCount)
549547
} else {
550548
// disable custom loop count
551-
view.wrapped.shouldCustomLoopCount = false
549+
view.shouldCustomLoopCount = false
552550
}
553551

554552
// RunLoop Mode
555553
if let runLoopMode = imageConfiguration.runLoopMode {
556-
view.wrapped.runLoopMode = runLoopMode
554+
view.runLoopMode = runLoopMode
557555
} else {
558-
view.wrapped.runLoopMode = .common
556+
view.runLoopMode = .common
559557
}
560558

561559
// Pausable
562560
if let pausable = imageConfiguration.pausable {
563-
view.wrapped.resetFrameIndexWhenStopped = !pausable
561+
view.resetFrameIndexWhenStopped = !pausable
564562
} else {
565-
view.wrapped.resetFrameIndexWhenStopped = false
563+
view.resetFrameIndexWhenStopped = false
566564
}
567565

568566
// Clear Buffer
569567
if let purgeable = imageConfiguration.purgeable {
570-
view.wrapped.clearBufferWhenStopped = purgeable
568+
view.clearBufferWhenStopped = purgeable
571569
} else {
572-
view.wrapped.clearBufferWhenStopped = false
570+
view.clearBufferWhenStopped = false
573571
}
574572

575573
// Playback Rate
576574
if let playbackRate = imageConfiguration.playbackRate {
577-
view.wrapped.playbackRate = playbackRate
575+
view.playbackRate = playbackRate
578576
} else {
579-
view.wrapped.playbackRate = 1.0
577+
view.playbackRate = 1.0
580578
}
581579

582580
// Playback Mode
583581
if let playbackMode = imageConfiguration.playbackMode {
584-
view.wrapped.playbackMode = playbackMode
582+
view.playbackMode = playbackMode
585583
} else {
586-
view.wrapped.playbackMode = .normal
584+
view.playbackMode = .normal
587585
}
588586

589587
// Animation
590588
#if os(macOS)
591-
if self.isAnimating != view.wrapped.animates {
592-
view.wrapped.animates = self.isAnimating
589+
if self.isAnimating != view.animates {
590+
view.animates = self.isAnimating
593591
}
594592
#else
595-
if self.isAnimating != view.wrapped.isAnimating {
593+
if self.isAnimating != view.isAnimating {
596594
if self.isAnimating {
597-
view.wrapped.startAnimating()
595+
view.startAnimating()
598596
} else {
599-
view.wrapped.stopAnimating()
597+
view.stopAnimating()
600598
}
601599
}
602600
#endif

SDWebImageSwiftUI/Classes/ImageViewWrapper.swift

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,10 @@ import SwiftUI
1414

1515
/// Use wrapper to solve tne `UIImageView`/`NSImageView` frame size become image size issue (SwiftUI's Bug)
1616
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
17-
public class AnimatedImageViewWrapper : PlatformView {
18-
/// The wrapped actual image view, using SDWebImage's aniamted image view
19-
public var wrapped = SDAnimatedImageView()
17+
public class AnimatedImageViewWrapper : SDAnimatedImageView {
2018
var interpolationQuality = CGInterpolationQuality.default
2119
var shouldAntialias = false
2220
var resizingMode: Image.ResizingMode?
23-
var imageSize: CGSize?
2421

2522
public override func draw(_ rect: CGRect) {
2623
#if os(macOS)
@@ -36,29 +33,9 @@ public class AnimatedImageViewWrapper : PlatformView {
3633
ctx.setShouldAntialias(shouldAntialias)
3734
}
3835

39-
#if os(macOS)
40-
public override func layout() {
41-
super.layout()
42-
wrapped.frame = self.bounds
43-
}
44-
#else
45-
public override func layoutSubviews() {
46-
super.layoutSubviews()
47-
wrapped.frame = self.bounds
48-
}
49-
#endif
50-
5136
public override var intrinsicContentSize: CGSize {
5237
/// 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-
}
38+
let contentSize = super.intrinsicContentSize
6239
if let _ = resizingMode {
6340
/// Keep aspect ratio
6441
if contentSize.width > 0 && contentSize.height > 0 {
@@ -73,16 +50,6 @@ public class AnimatedImageViewWrapper : PlatformView {
7350
return contentSize
7451
}
7552
}
76-
77-
public override init(frame frameRect: CGRect) {
78-
super.init(frame: frameRect)
79-
addSubview(wrapped)
80-
}
81-
82-
public required init?(coder: NSCoder) {
83-
super.init(coder: coder)
84-
addSubview(wrapped)
85-
}
8653
}
8754

8855
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)

0 commit comments

Comments
 (0)