SwiftUI:实现无自动反转的永久循环动画并在动画结束后添加延迟的方法
解决SwiftUI永久循环动画结束后添加停顿的问题
嘿,我完全懂你的困扰——默认的repeatForever确实会在动画结束后立刻跳回初始状态,而.delay()只作用于动画的启动阶段,完全不是你想要的“结束后停顿”效果。别担心,这里有两种靠谱的方法可以实现你要的需求:
方法一:用动画序列组合动画与停顿(iOS 15+)
SwiftUI在iOS 15及以上提供了Animation.sequence()方法,允许你把多个动画按顺序组合起来。我们可以把“实际动画”和“无变化的停顿动画”打包成一个序列,再让这个序列永久重复:
// 假设动画时长1秒,停顿1秒,总周期2秒 let cycleAnimation = Animation.sequence([ .easeInOut(duration: 1), // 执行你的核心动画(比如尺寸变化、位移等) .linear(duration: 1) // 用一个无变化的线性动画实现停顿(保持最后一帧状态) ]).repeatForever(autoreverses: false)
使用的时候,直接把这个动画绑定到你的视图属性上即可,比如:
@State private var isExpanded = false var body: some View { Circle() .frame(width: isExpanded ? 200 : 100, height: isExpanded ? 200 : 100) .onAppear { withAnimation(cycleAnimation) { isExpanded = true } } }
这个方法的好处是完全利用SwiftUI的原生动画系统,不需要手动管理循环逻辑。
方法二:手动触发动画循环(兼容iOS 13+)
如果需要支持更低版本的iOS,你可以用DispatchQueue手动控制动画的触发时机,在每次动画完成后添加延迟,再重置状态并开始下一轮:
@State private var isAnimating = false var body: some View { Rectangle() .foregroundColor(.blue) .frame(width: isAnimating ? 300 : 100, height: isAnimating ? 300 : 100) .onAppear { startAnimationCycle() } } private func startAnimationCycle() { // 执行动画:从初始状态到目标状态 withAnimation(.easeInOut(duration: 1)) { isAnimating = true } // 等待动画完成(1秒)+ 停顿(1秒),然后重置状态 DispatchQueue.main.asyncAfter(deadline: .now() + 1 + 1) { // 无动画跳回初始状态(避免突兀跳转) withAnimation(.linear(duration: 0)) { isAnimating = false } // 立刻启动下一轮循环 startAnimationCycle() } }
为什么你之前的方法无效?
- 当你把
.delay(1)放在.repeatForever()前面时,它只会让第一次动画延迟1秒启动,之后的循环还是会立刻重复。 - 把
.delay(1)放在.repeatForever()后面时,延迟是作用于整个重复序列的启动,而不是每次循环之间的间隔,所以完全看不到效果。
内容的提问来源于stack exchange,提问作者ixany
相关产品推荐
相关产品推荐

