LazyVGrid中VStack包裹AsyncImage滚动时图片重加载如何解决?
问题根因
这个现象的本质是LazyVGrid的懒加载复用机制要求子视图拥有可预判的尺寸,你当前没有给VStack添加明确的尺寸约束,滚动时视图被回收后重新进入可视区,SwiftUI会重新计算VStack的布局并重建内部所有子视图,导致AsyncImage被重新初始化,触发重复加载。
解决方法
方法1:给VStack添加明确的固定尺寸
直接指定VStack的宽高,让LazyVGrid可以直接复用回收的视图,无需重新构造内部的AsyncImage,即可解决重复加载问题,同时你也可以在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, id: \.self) { index in VStack(spacing: 6) { AsyncImage(url: url) { image in image .resizable() .aspectRatio(contentMode: .fit) .frame(width: 110, height: 110) } placeholder: { Image(systemName: "photo") .imageScale(.large) .frame(width: 110, height: 110) } // 可自由添加图片标题 Text("图片\(index + 1)") .font(.caption) .lineLimit(1) } // 明确指定VStack的总尺寸,适配图片+文本的高度 .frame(width: 110, height: 136) } } } } }
方法2:固定AsyncImage的尺寸
如果不想给VStack写死高度,也可以保证AsyncImage的加载状态、占位状态的尺寸完全一致,这样VStack的尺寸可以被SwiftUI提前计算出来,也不会触发视图重建。
使用这种方法时,只需要给AsyncImage外层加固定宽高的frame即可,不需要给VStack指定高度。
方法3:使用稳定的视图ID
给ForEach添加稳定的唯一ID,避免滚动时视图ID变化导致的视图重建,业务场景中推荐使用图片的唯一标识或者URL作为ID。
内容的提问来源于stack exchange,提问作者Maklaus
相关产品推荐
相关产品推荐

