SwiftUI列表动画切换真实数据后异常的解决方法
SwiftUI排名列表动画在动态数据下异常,移除removeAll后恢复正常
问题概述
为游戏总分列表实现了动画效果:保存用户历史结果,下次打开视图时,用户的结果条目会从旧排名位置平滑移动到新位置。测试阶段用硬编码假数据时动画表现正常,但切换为服务器返回的动态数据后,动画出现严重异常。
排查后确认问题核心在ViewModel的setResultData方法中:
- 使用动态生成的
oldResults时动画异常 - 硬编码假数据时动画正常
- 移除
removeAll(where: {$0.uuid == previousResult.uuid})语句后,动画恢复正常
代码示例
1. Model定义
struct ScoreResult: Identifiable { let id = UUID() let uuid: String let userName: String let score: Int // 其他业务字段 }
2. ViewModel核心代码
class ScoreViewModel: ObservableObject { @Published var results: [ScoreResult] = [] private var previousResult: ScoreResult? private let currentUserUUID = "user_123" // 示例用户UUID func setResultData(newResults: [ScoreResult]) { // 动态生成旧数据集合(触发异常的场景) var oldResults = self.results // 保存当前用户的历史结果 previousResult = oldResults.first(where: { $0.uuid == currentUserUUID }) // 问题代码:移除该行后动画恢复正常 // oldResults.removeAll(where: {$0.uuid == previousResult?.uuid}) // 执行动画更新数据 withAnimation { self.results = newResults } } // 从服务器获取动态数据 func fetchResultsFromServer() async { let fetchedResults = await APIManager.getScoreResults() DispatchQueue.main.async { self.setResultData(newResults: fetchedResults) } } } // 模拟API请求工具类 struct APIManager { static func getScoreResults() async -> [ScoreResult] { // 模拟服务器返回动态数据 return [ ScoreResult(uuid: "user_456", userName: "PlayerA", score: 980), ScoreResult(uuid: "user_123", userName: "Me", score: 920), ScoreResult(uuid: "user_789", userName: "PlayerB", score: 850) ] } }
3. SwiftUI视图代码
struct ScoreListView: View { @StateObject private var viewModel = ScoreViewModel() var body: some View { List(viewModel.results) { result in HStack { Text(result.userName) Spacer() Text("\(result.score)") } } .onAppear { Task { await viewModel.fetchResultsFromServer() } } } }
动画效果对比
- 正常动画:用户条目从旧排名位置平滑过渡到新位置,其他条目同步自然调整位置,无跳动、闪烁或布局混乱
- 异常动画:条目出现突兀跳转、闪烁,部分条目位置瞬间变化,完全失去平滑过渡效果
内容的提问来源于stack exchange,提问作者Christopher
相关产品推荐
相关产品推荐

