如何让SwiftUI列表仅首次显示的缩略图加载时执行动画
SwiftData缩略图加载动画优化方案
核心思路
要实现仅首次可见区域的缩略图执行淡入动画,后续滚动(包括回滚)不再重复动画,需同时控制全局首次加载状态和单个缩略图的动画执行标记:
- 用全局状态标记首次加载阶段是否结束,完成后所有新出现的缩略图不再触发动画
- 给每个图片数据添加已执行动画的标记,避免回滚时已显示过的缩略图重复执行动画
具体实现步骤
给数据模型添加动画标记
在SwiftData的图片模型中新增布尔属性,记录该图片是否已经执行过加载动画。父视图控制全局加载状态
在ImageLibraryView中添加状态变量,标记首次加载阶段是否结束。缩略图视图根据条件触发动画
在ThumbnailView中,仅当全局处于首次加载阶段且该图片未执行过动画时,才触发淡入动画。
代码示例
1. SwiftData模型定义
import SwiftData @Model class ImageAsset { let id: UUID let imageFilePath: String var hasCompletedAnimation: Bool // 标记是否已执行过加载动画 init(id: UUID = UUID(), imageFilePath: String, hasCompletedAnimation: Bool = false) { self.id = id self.imageFilePath = imageFilePath self.hasCompletedAnimation = hasCompletedAnimation } }
2. 缩略图视图实现
struct ThumbnailView: View { @Bindable var asset: ImageAsset let shouldAnimate: Bool private var thumbnailImage: UIImage? { UIImage(contentsOfFile: asset.imageFilePath) } var body: some View { Group { if let image = thumbnailImage { Image(uiImage: image) .resizable() .scaledToFill() } else { Color.gray.opacity(0.3) } } .frame(width: 100, height: 100) .clipped() .opacity(shouldAnimate ? 0 : 1) .animation(shouldAnimate ? .easeIn(duration: 0.3) : nil, value: shouldAnimate) .onAppear { guard shouldAnimate else { return } // 动画触发后标记该图片已完成动画 DispatchQueue.main.async { withAnimation { asset.hasCompletedAnimation = true } } } } }
3. 图片库列表视图实现
struct ImageLibraryView: View { @Query private var imageAssets: [ImageAsset] @State private var isFirstLoadFinished = false @State private var firstLoadAssetIDs = Set<UUID>() var body: some View { ScrollView { LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3)) { ForEach(imageAssets) { asset in let animateCondition = !isFirstLoadFinished && !asset.hasCompletedAnimation && !firstLoadAssetIDs.contains(asset.id) ThumbnailView(asset: asset, shouldAnimate: animateCondition) .onAppear { guard !isFirstLoadFinished else { return } firstLoadAssetIDs.insert(asset.id) // 延迟标记首次加载完成,确保可见区域的缩略图都有机会触发动画 DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { isFirstLoadFinished = true } } } } .padding() } } }
关键细节说明
- 全局状态
isFirstLoadFinished:首次加载完成后,所有后续出现的缩略图直接跳过动画逻辑 - 模型属性
hasCompletedAnimation:确保回滚时已显示过的缩略图不会重复执行动画 - 延迟标记首次加载完成:LazyVGrid的单元格按需加载,首次可见单元格不会同时触发
onAppear,0.6秒延迟可保证大部分可见缩略图完成动画后再关闭全局动画开关
内容的提问来源于stack exchange,提问作者RRR
相关产品推荐
相关产品推荐

