Update the logic to be compatible with LazyVStack's resetting status behavior

This commit is contained in:
DreamPiggy 2021-02-22 17:05:56 +08:00
parent 3a7132a499
commit 66ca5fbb83
1 changed files with 42 additions and 25 deletions

View File

@ -44,7 +44,7 @@ final class AnimatedLoadingModel : ObservableObject, IndicatorReportable {
@Published var isLoading: Bool = false // whether network is loading or cache is querying, should only be used for indicator binding
@Published var progress: Double = 0 // network progress, should only be used for indicator binding
/// Used for loading status recording to avoid recursive `updateView`. There are 3 types of loading (Name/Data/URL)
/// Used for loading status recording to avoid recursive `updateView`. There are 3 types of loading (Name/Data/URL)
@Published var imageName: String?
@Published var imageData: Data?
@Published var imageURL: URL?
@ -206,12 +206,27 @@ public struct AnimatedImage : PlatformViewRepresentable {
}
#endif
func loadImage(_ view: AnimatedImageViewWrapper, context: Context) {
let operationKey = NSStringFromClass(type(of: view.wrapped))
let currentOperation = view.wrapped.sd_imageLoadOperation(forKey: operationKey)
if currentOperation != nil {
return
func setupIndicator(_ view: AnimatedImageViewWrapper, context: Context) {
view.wrapped.sd_imageIndicator = imageConfiguration.indicator
view.wrapped.sd_imageTransition = imageConfiguration.transition
if let placeholderView = imageConfiguration.placeholderView {
placeholderView.removeFromSuperview()
placeholderView.isHidden = true
// Placeholder View should below the Indicator View
if let indicatorView = imageConfiguration.indicator?.indicatorView {
#if os(macOS)
view.wrapped.addSubview(placeholderView, positioned: .below, relativeTo: indicatorView)
#else
view.wrapped.insertSubview(placeholderView, belowSubview: indicatorView)
#endif
} else {
view.wrapped.addSubview(placeholderView)
}
placeholderView.bindFrameToSuperviewBounds()
}
}
func loadImage(_ view: AnimatedImageViewWrapper, context: Context) {
self.imageLoading.isLoading = true
let options = imageModel.webOptions
if options.contains(.delayPlaceholder) {
@ -234,9 +249,9 @@ public struct AnimatedImage : PlatformViewRepresentable {
self.imageHandler.progressBlock?(receivedSize, expectedSize)
}) { (image, data, error, cacheType, finished, _) in
if #available(iOS 14.0, macOS 11.0, watchOS 7.0, tvOS 14.0, *) {
// Do nothing
// Do nothing. on iOS 14's SwiftUI, the @Published will always trigger another `updateUIView` call with new UIView instance.
} else {
// This is a hack because of Xcode 11.3 bug, the @Published does not trigger another `updateUIView` call
// This is a hack because of iOS 13's SwiftUI bug, the @Published does not trigger another `updateUIView` call
// Here I have to use UIKit/AppKit API to triger the same effect (the window change implicitly cause re-render)
if let hostingView = AnimatedImage.findHostingView(from: view) {
if let _ = hostingView.window {
@ -284,26 +299,28 @@ public struct AnimatedImage : PlatformViewRepresentable {
let image = SDAnimatedImage(data: data, scale: imageModel.scale)
imageLoading.imageData = data
view.wrapped.image = image
} else if let url = imageModel.url, url != imageLoading.imageURL {
imageLoading.imageURL = url
view.wrapped.sd_imageIndicator = imageConfiguration.indicator
view.wrapped.sd_imageTransition = imageConfiguration.transition
if let placeholderView = imageConfiguration.placeholderView {
placeholderView.removeFromSuperview()
placeholderView.isHidden = true
// Placeholder View should below the Indicator View
if let indicatorView = imageConfiguration.indicator?.indicatorView {
#if os(macOS)
view.wrapped.addSubview(placeholderView, positioned: .below, relativeTo: indicatorView)
#else
view.wrapped.insertSubview(placeholderView, belowSubview: indicatorView)
#endif
} else if let url = imageModel.url {
// Determine if image already been loaded and URL is match
var shouldLoad: Bool
if url != imageLoading.imageURL {
// Change the URL, need new loading
shouldLoad = true
imageLoading.imageURL = url
} else {
// Same URL, check if already loaded
if imageLoading.isLoading {
shouldLoad = false
} else if let image = imageLoading.image {
shouldLoad = false
view.wrapped.image = image
} else {
view.wrapped.addSubview(placeholderView)
shouldLoad = true
}
placeholderView.bindFrameToSuperviewBounds()
}
loadImage(view, context: context)
if shouldLoad {
setupIndicator(view, context: context)
loadImage(view, context: context)
}
}
#if os(macOS)