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

SwiftUI环形点击动画反向而非停止,如何让其重置为初始状态?

问题:环形动画点击后无法重置为初始状态,反向播放异常

我实现了一个按钮触发的环形动画,预期点击按钮时动画停止并重置为初始状态,但实际出现异常:点击第二次时动画反向播放而非重置为0。如何修改代码实现点击后重置为初始状态?

带环形动画的按钮

原代码如下:

struct ContentView: View {
   
    @State private var animationActive = false
    
    let animation = Animation
            .linear(duration: 10)
    
    var body: some View {
        ZStack {
            GeometryReader {geo in
                        ZStack {
                            //Image("RecordButton")
                            Button {
                                animationActive.toggle()
                            } label: {
                                Image("RecordButton")
                            }
                            ring(for: Color.white)
                                .animation(animation, value: animationActive)
                        }
            }.edgesIgnoringSafeArea(.all)
        }
    }
    
    func ring(for color: Color) -> some View {
        // Background ring
        Circle()
            .stroke(style: StrokeStyle(lineWidth: 20))
            .frame(width: 250)
            .foregroundStyle(.tertiary)
            .overlay {
                // Foreground ring
                Circle()
                    .trim(from: 0, to: animationActive ? 1 : 0)
                    .stroke(color.gradient,
                            style: StrokeStyle(lineWidth: 20, lineCap: .round))
                    .frame(width: 250)
            }
            .rotationEffect(.degrees(-90))
    }
}

解决方案

问题根源在于用布尔值animationActive控制动画时,SwiftUI默认会对状态切换执行反向过渡动画。要实现点击后直接重置到初始状态,需要改用进度值精准控制,并通过显式动画触发逻辑来规避反向动画。

修改后的完整代码:

struct ContentView: View {
    // 用Double类型的进度值替代布尔状态,直接控制环形裁剪范围
    @State private var ringProgress = 0.0
    
    let animation = Animation.linear(duration: 10)
    
    var body: some View {
        ZStack {
            GeometryReader { _ in
                ZStack {
                    Button {
                        if ringProgress > 0 {
                            // 直接将进度设为0,瞬间回到初始状态
                            ringProgress = 0
                        } else {
                            // 显式启动从0到1的线性动画
                            withAnimation(animation) {
                                ringProgress = 1
                            }
                        }
                    } label: {
                        Image("RecordButton")
                    }
                    ring(for: .white)
                }
            }.edgesIgnoringSafeArea(.all)
        }
    }
    
    func ring(for color: Color) -> some View {
        Circle()
            .stroke(style: StrokeStyle(lineWidth: 20))
            .frame(width: 250)
            .foregroundStyle(.tertiary)
            .overlay {
                Circle()
                    // 使用进度值控制环形的裁剪范围
                    .trim(from: 0, to: ringProgress)
                    .stroke(color.gradient, style: StrokeStyle(lineWidth: 20, lineCap: .round))
                    .frame(width: 250)
            }
            .rotationEffect(.degrees(-90))
    }
}

关键修改点:

  • 状态变量替换:将animationActive布尔值改为ringProgress双精度值,直接映射环形的trim参数,避免布尔切换带来的默认反向动画。
  • 点击逻辑优化:按钮点击时判断当前进度:若进度大于0(动画中或已完成),直接重置为0;若进度为0,则通过withAnimation启动正向动画。
  • 动画控制方式调整:移除原有的.animation修饰符,改用显式withAnimation触发动画,让动画行为完全由业务逻辑控制。

内容的提问来源于stack exchange,提问作者Mr. Man

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 07:12:37