Swift中如何实现数字滚动动画?(步数统计场景)
问题描述
我想实现数字从0快速递增到当前数值的动画效果,这个数值是用户的步数。现有SwiftUI代码通过LazyVStack展示步数:
LazyVStack{ ForEach(steps, id: \.id) { step in // 这里是需要加动画的数字 Text("\(step.count)") .font(.custom(customFont, size: 50)) Text("Steps") .font(.custom(customFont, size: 25)) .multilineTextAlignment(.center) } }
我已经写了一个动画函数,需要把它应用到上面的步数文本上:
func addNumberWithRollingAnimation() { withAnimation { // 确定动画任务数 let animationDuration = 1000 // 毫秒 let tasks = min(abs(self.enteredNumber), 100) let taskDuration = (animationDuration / tasks) // 先加上余数部分 total += self.enteredNumber % tasks // 遍历每个任务 (0..<tasks).forEach { task in // 设置更新时间 let updateTimeInterval = DispatchTimeInterval.milliseconds(task * taskDuration) let deadline = DispatchTime.now() + updateTimeInterval // 到时间后更新数值 DispatchQueue.main.asyncAfter(deadline: deadline) { self.total += Int(self.enteredNumber / tasks) } } } }
请问怎么把这个函数应用到步数文本上,实现数字滚动动画?
解决方案
1. 调整数据模型,新增动画用动态属性
你的steps数组元素(假设是Step结构体)需要添加一个用于动画的动态数值属性,用来逐步递增到目标步数:
struct Step: Identifiable { let id = UUID() let count: Int // 最终目标步数 var animatedCount: Int = 0 // 动画过程中实时更新的数值 }
2. 适配动画函数,支持单个Step的动画
原函数是针对全局数值的,现在修改为可以处理单个Step的版本,传入目标数值和动态数值的引用:
func animateStepCount(to target: Int, animatedCount: inout Int) { let animationDuration = 1000 // 动画总时长(毫秒) let tasks = min(abs(target), 100) // 拆分动画步骤,最多100次避免刷新过于频繁 guard tasks > 0 else { return } let increment = target / tasks let remainder = target % tasks // 重置动画起始值为0 animatedCount = 0 // 先补上余数部分,保证最终数值准确 DispatchQueue.main.asyncAfter(deadline: .now()) { animatedCount += remainder } // 分批递增数值,实现滚动效果 (0..<tasks).forEach { task in let interval = DispatchTimeInterval.milliseconds(task * (animationDuration / tasks)) DispatchQueue.main.asyncAfter(deadline: .now() + interval) { animatedCount += increment } } }
3. 在视图中绑定动态数值并触发动画
在LazyVStack的ForEach中使用绑定来访问step.animatedCount,并在视图出现时启动动画:
LazyVStack{ ForEach($steps) { $step in // 使用绑定类型,让视图能响应animatedCount的变化 Text("\(step.animatedCount)") .font(.custom(customFont, size: 50)) .onAppear { // 视图加载完成后,启动从0到目标步数的滚动动画 animateStepCount(to: step.count, animatedCount: &step.animatedCount) } Text("Steps") .font(.custom(customFont, size: 25)) .multilineTextAlignment(.center) } }
关键注意事项
- 确保
steps数组由@State、@ObservedObject或@EnvironmentObject管理,这样修改animatedCount时视图才会自动刷新。 - 如果后续步数有更新,只需再次调用
animateStepCount函数,传入新的目标数值即可重新触发动画。
内容的提问来源于stack exchange,提问作者Mxyb
相关产品推荐
相关产品推荐

