如何为ScrollView/LazyVGrid中API获取的数据添加动画效果?
解决方案:实现数据加载时的流畅动画效果
一、修正数据加载时机,确保首次视图出现即触发请求
当前.task附加在LazyVGrid上,首次打开时LazyVGrid可能还未完成渲染,导致请求触发延迟或动画不同步。将加载任务移到ScrollView层级,确保视图出现就执行数据请求:
ScrollView { // ... 原有内容 } .task { if selectedSegmentedOption == .myPresentations { await viewModel.getAllPresentations(page: 1, pageSize: 10) } } .background(CustomColor.background.swiftUIColor)
二、在ViewModel中用withAnimation包裹数据更新
确保数据更新时通知SwiftUI触发动画,修改PresentationsViewModel中的getAllPresentations方法:
func getAllPresentations(page: Int, pageSize: Int) async { // ... 原有数据请求逻辑 let fetchedData = // 从接口获取的数据 withAnimation { self.myPresentations = fetchedData self.shouldShowEmptyScreen = fetchedData.isEmpty } }
三、给列表项添加入场动画
修改PresentationRootView中的LazyVGrid,为每个列表项添加过渡动画:
LazyVGrid(columns: columns, spacing: 4, content: { ForEach($viewModel.myPresentations, id: \.ID) { element in PresentationSingleView(url: element.ThumbURLWithSas.wrappedValue, title: element.Name.wrappedValue, numberOfResources: 4) .padding([.leading, .trailing], 13) .transition(.opacity.combined(with: .scale)) // 添加过渡动画 } })
四、优化图片加载的过渡动画
在PresentationSingleView中,给图片添加平滑的显示过渡,同时添加占位图保持布局稳定:
// 替换原来的image.view?部分 Group { if let imageView = image.view { imageView .resizable() .scaledToFill() .frame(maxWidth: isIphone ? 90 : 140, maxHeight: isIphone ? 64 : 140) .cornerRadius(4) .padding(isIphone ? 10 : 20) .transition(.opacity) // 图片加载完成的过渡 } else { // 加载占位图 Color.gray.opacity(0.2) .frame(maxWidth: isIphone ? 90 : 140, maxHeight: isIphone ? 64 : 140) .cornerRadius(4) .padding(isIphone ? 10 : 20) } } .animation(.easeInOut(duration: 0.3), value: image.view)
五、处理空视图的切换动画
给空视图和列表的切换添加过渡,避免生硬跳转:
ScrollView { if selectedSegmentedOption == .myPresentations { if viewModel.shouldShowEmptyScreen { Text("No data") .transition(.opacity) } else { LazyVGrid(columns: columns, spacing: 4, content: { // ... 原有列表项内容 }) .transition(.opacity.combined(with: .slide)) } } } .animation(.easeInOut(duration: 0.3), value: viewModel.shouldShowEmptyScreen)
关键前提
确保myPresentations是ViewModel中的@Published属性,这样数据变化才能正确通知View更新:
class PresentationsViewModel: ObservableObject { @Published var myPresentations: [YourModelType] = [] @Published var shouldShowEmptyScreen = true // ... 其他代码 }
内容的提问来源于stack exchange,提问作者Nikola
相关产品推荐
相关产品推荐

