You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 16:13:11