From d9fd4726eaf1a8816c765986de8b9d5d111e65f9 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 31 Mar 2020 17:24:47 +0800 Subject: [PATCH] Using a more trick but smart solution for cases when WebImage is used during transition state, like scaleEffect. In this time, we does not trigger a actualy image loading, only query the memory cache for quickly placeholder --- Example/SDWebImageSwiftUIDemo/DetailView.swift | 8 ++++---- SDWebImageSwiftUI/Classes/ImageManager.swift | 17 +++++++++++++++++ SDWebImageSwiftUI/Classes/WebImage.swift | 16 +++++++++------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Example/SDWebImageSwiftUIDemo/DetailView.swift b/Example/SDWebImageSwiftUIDemo/DetailView.swift index eacbbd2..f3cf15c 100644 --- a/Example/SDWebImageSwiftUIDemo/DetailView.swift +++ b/Example/SDWebImageSwiftUIDemo/DetailView.swift @@ -38,7 +38,7 @@ struct DetailView: View { let url: String let animated: Bool @State var isAnimating: Bool = true - @State var lastScaleValue: CGFloat = 1.0 + @State var lastScale: CGFloat = 1.0 @State var scale: CGFloat = 1.0 @Environment(\.presentationMode) var presentationMode @EnvironmentObject var settings: UserSettings @@ -75,12 +75,12 @@ struct DetailView: View { return contentView() .scaleEffect(self.scale) .gesture(MagnificationGesture(minimumScaleDelta: 0.1).onChanged { value in - let delta = value / self.lastScaleValue - self.lastScaleValue = value + let delta = value / self.lastScale + self.lastScale = value let newScale = self.scale * delta self.scale = min(max(newScale, 0.5), 2) }.onEnded { value in - self.lastScaleValue = 1.0 + self.lastScale = 1.0 }) #endif #if os(tvOS) diff --git a/SDWebImageSwiftUI/Classes/ImageManager.swift b/SDWebImageSwiftUI/Classes/ImageManager.swift index 7726769..a148a2e 100644 --- a/SDWebImageSwiftUI/Classes/ImageManager.swift +++ b/SDWebImageSwiftUI/Classes/ImageManager.swift @@ -106,6 +106,23 @@ public final class ImageManager : ObservableObject { } } + /// Prefetch the initial state of image + internal func prefetch() { + let key = manager.cacheKey(for: url) + if let imageCache = manager.imageCache as? SDImageCache { + self.image = imageCache.imageFromMemoryCache(forKey: key) + } else { + // generic API + manager.imageCache.containsImage(forKey: key, cacheType: .memory) { [unowned self] (cacheType) in + if cacheType == .memory { + self.manager.imageCache.queryImage(forKey: key, options: self.options, context: self.context) { [unowned self] (image, data, cacheType) in + self.image = image + } + } + } + } + } + } // Completion Handler diff --git a/SDWebImageSwiftUI/Classes/WebImage.swift b/SDWebImageSwiftUI/Classes/WebImage.swift index 424552d..bbb04ae 100644 --- a/SDWebImageSwiftUI/Classes/WebImage.swift +++ b/SDWebImageSwiftUI/Classes/WebImage.swift @@ -57,16 +57,13 @@ public struct WebImage : View { } } self.imageManager = ImageManager(url: url, options: options, context: context) + // this prefetch the memory cache of image, to immediately render it on screen + // this solve the cause when `onAppear` not been called, for example, some transaction indetermite state :) + self.imageManager.prefetch() } public var body: some View { - // load remote image when first called `body`, SwiftUI sometimes will create a new View struct without calling `onAppear` (like enter EditMode) :) - // this can ensure we load the image, and display image synchronously when memory cache hit to avoid flashing - // called once per struct, SDWebImage take care of the duplicated query - if imageManager.isFirstLoad { - imageManager.load() - } - return Group { + Group { if imageManager.image != nil { if isAnimating && !self.imageManager.isIncremental { if currentFrame != nil { @@ -109,6 +106,11 @@ public struct WebImage : View { setupPlaceholder() .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) .onAppear { + // load remote image when first appear + if self.imageManager.isFirstLoad { + self.imageManager.load() + return + } guard self.retryOnAppear else { return } // When using prorgessive loading, the new partial image will cause onAppear. Filter this case if self.imageManager.image == nil && !self.imageManager.isIncremental {