SwiftUI动画:如何让重复动画的时长逐次递减?
解决方案:手动链式触发递减时长的动画
直接使用withAnimation配合repeatCount无法实现每次重复时长递减的需求,因为重复动画会复用同一个动画配置,所有重复周期的时长都是相同的。要实现每次时长递减,需要手动逐个触发动画,利用动画的完成回调来衔接下一次周期。
以下是具体实现代码:
struct YourView: View { let imagename: String @State private var scale: CGFloat = 1.0 // 剩余需要执行的缩放周期数 @State private var remainingCycles = 5 // 当前动画的单向时长(对应你原来的0.5秒缩放时长) @State private var currentSingleDuration = 0.5 var body: some View { ImageView(named: imagename) .padding(.trailing, 16) .padding(.top, 105) .scaleEffect(scale) .onAppear { startScalingCycle() } } private func startScalingCycle() { // 剩余周期为0时停止动画 guard remainingCycles > 0 else { return } // 配置当前周期的动画:单向时长currentSingleDuration,自动反向回到初始状态 let animation = Animation.easeInOut(duration: currentSingleDuration) .autoreverses(true) withAnimation(animation) { scale = 0.5 } completion: { // 动画完成(包括反向还原)后,更新参数并触发下一次 remainingCycles -= 1 // 时长递减0.1秒,同时避免时长过小导致异常 currentSingleDuration = max(currentSingleDuration - 0.1, 0.1) // 递归触发下一个周期 startScalingCycle() } } }
代码说明:
- 使用
remainingCycles跟踪还需执行的完整缩放-还原周期数,初始值设为你需要的5次 currentSingleDuration记录当前动画的单向时长,每次完成后递减0.1秒,并用max限制最小时长(避免出现0或负数时长)- 每个周期通过
autoreverses(true)自动实现从缩放状态还原到初始状态,和你原代码的动画行为一致 - 动画完成的
completion回调是关键,在这里更新参数并递归触发下一次动画,实现链式的时长递减效果
可选调整:
如果你想要的是整个缩放-还原周期的总时长递减0.1秒(比如第一次总时长0.5秒,第二次0.4秒),可以修改代码中的时长计算逻辑:
@State private var totalCycleDuration = 0.5 // 总周期时长 private func startScalingCycle() { guard remainingCycles > 0 else { return } let singleDuration = totalCycleDuration / 2 let animation = Animation.easeInOut(duration: singleDuration) .autoreverses(true) withAnimation(animation) { scale = 0.5 } completion: { remainingCycles -= 1 totalCycleDuration = max(totalCycleDuration - 0.1, 0.1) startScalingCycle() } }
内容的提问来源于stack exchange,提问作者stefanosn
相关产品推荐
相关产品推荐

