在 LazyVStack 中使用带有 AsyncImage 的 VStack 会导致图像在滚动时重新加载

Using VStack with AsyncImage inside LazyVStack causes images to reload on scrolling

我正在尝试使用 SwiftUI 中的新 AsyncImage 显示一长串带标题的图像。我注意到,当我将 VStack 放在 AsyncImage 周围并滚动图像时,它会在我每次向上或向下滚动时重新加载图像。当没有 VStack 时,我看不到重新加载并且图像似乎保持缓存状态。

有没有办法让 VStack 在滚动时不重新加载图像,以便我可以在每个图像下添加文本?​​

这是一个工作示例。尝试使用和不使用 VStack 进行滚动。

import SwiftUI

struct TestView: View {

    let url = URL(string: "https://picsum.photos/200/300")

    let columns: [GridItem] = [.init(.fixed(110)),.init(.fixed(110)),.init(.fixed(110))]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns) {
                ForEach(0..<20) { _ in
                    // VStack here causes to images to reload on scrolling
                    VStack {
                        AsyncImage(url: url) { image in
                            image
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                        } placeholder: {
                            Image(systemName: "photo")
                                .imageScale(.large)
                                .frame(width: 110, height: 110)
                        }
                    }
                }
            }
        }
    }
}

我完全同意你的看法,这是一个奇怪的错误。我猜它发生的原因与 LazyVGrid 选择布局视图的方式有关,并且在这里使用 VStack 给人的印象是要显示多个视图。这对 Apple 来说是一个糟糕的工作,但这就是我解决它的方法:只需将 VStacks 放在 AsyncImage 内部。我不完全确定最初的错误是什么,但我知道这会修复它。

struct MyTestView: View {
    let url = URL(string: "https://picsum.photos/200/300")
    let columns: [GridItem] = [.init(.fixed(110)),.init(.fixed(110)),.init(.fixed(110))]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns) {
                ForEach(0..<20) { i in
                    AsyncImage(url: url) { image in
                        VStack {
                            image
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                            
                            Text("label \(i)")
                        }
                    } placeholder: {
                        VStack {
                            Image(systemName: "photo")
                                .imageScale(.large)
                                .frame(width: 110, height: 110)
                            
                            Text("image broken")
                        }
                    }
                }
            }
        }
    }
}