Explorar o código

Merge pull request #2017 from onevcat/fix/load-before-view-appear

Add an option to start image loading before view appear
Wei Wang %!s(int64=3) %!d(string=hai) anos
pai
achega
67937479a0

+ 1 - 2
Sources/General/KFOptionsSetter.swift

@@ -442,8 +442,7 @@ extension KFOptionSetter {
     ///                         to form a processor pipeline.
     /// - Returns: A `Self` value with changes applied.
     ///
-    /// - Note:
-    /// To append processors to current ones instead of replacing them all, concatenate them by `|>`, then use
+    /// - Note: To append processors to current ones instead of replacing them all, concatenate them by `|>`, then use
     /// `appendProcessor(_:)`.
     public func setProcessors(_ processors: [ImageProcessor]) -> Self {
         switch processors.count {

+ 2 - 0
Sources/SwiftUI/ImageContext.swift

@@ -46,6 +46,8 @@ extension KFImage {
         let onSuccessDelegate = Delegate<RetrieveImageResult, Void>()
         let onProgressDelegate = Delegate<(Int64, Int64), Void>()
         
+        var startLoadingBeforeViewAppear: Bool = false
+        
         init(source: Source?) {
             self.source = source
         }

+ 20 - 0
Sources/SwiftUI/KFImageOptions.swift

@@ -134,5 +134,25 @@ extension KFImageProtocol {
         context.options.transition = .fade(duration)
         return self
     }
+    
+    /// Sets whether to start the image loading before the view actually appears.
+    ///
+    /// By default, Kingfisher performs a lazy loading for `KFImage`. The image loading won't start until the view's
+    /// `onAppear` is called. However, sometimes you may want to trigger an aggressive loading for the view. By enabling
+    /// this, the `KFImage` will try to load the view when its `body` is evaluated when the image loading is not yet
+    /// started or a previous loading did fail.
+    ///
+    /// - Parameter flag: Whether the image loading should happen before view appear. Default is `true`.
+    /// - Returns: A `KFImage` with changes applied.
+    ///
+    /// - Note: This is a temporary workaround for an issue from iOS 16, where the SwiftUI view's `onAppear` is not
+    /// called when it is deeply embedded inside a `List` or `ForEach`.
+    /// See [#1988](https://github.com/onevcat/Kingfisher/issues/1988). It may cause performance regression, especially
+    /// if you have a lot of images to load in the view. Use it as your own risk.
+    ///
+    public func startLoadingBeforeViewAppear(_ flag: Bool = true) -> Self {
+        context.startLoadingBeforeViewAppear = flag
+        return self
+    }
 }
 #endif

+ 5 - 1
Sources/SwiftUI/KFImageRenderer.swift

@@ -37,7 +37,11 @@ struct KFImageRenderer<HoldingView> : View where HoldingView: KFImageHoldingView
     let context: KFImage.Context<HoldingView>
     
     var body: some View {
-        ZStack {
+        if context.startLoadingBeforeViewAppear && !binder.loadingOrSucceeded {
+            DispatchQueue.main.async { binder.start(context: context) }
+        }
+        
+        return ZStack {
             context.configurations
                 .reduce(HoldingView.created(from: binder.loadedImage, context: context)) {
                     current, config in config(current)