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

SwiftUI切换状态时如何实现流畅连续的动画?

解决SwiftUI滑块切换时矩形旋转卡顿的问题

你的问题核心是使用.id(level)导致视图被重置,旋转状态丢失从而产生卡顿。以下是两种可行的平滑过渡方案:

方案一:基于SwiftUI动画系统无缝衔接

移除.id(level),通过动态调整动画时长并衔接当前旋转状态实现平滑切换:

struct ContentView: View {
    @State private var level: Double = 0
    @State private var rotation: Double = 0
    
    var body: some View {
        VStack(spacing: 16) {
            Rectangle().fill(.red)
                .frame(width: 100, height: 100)
                .rotationEffect(Angle(degrees: rotation))
                .animation(
                    level > 0 ? .linear(duration: 2 / level).repeatForever(autoreverses: false) : nil,
                    value: rotation
                )
            
            Spacer().frame(height: 12)
            Slider(value: $level, in: 0...3, step: 1)
            HStack {
                Text("0").fontWeight(.semibold)
                Spacer()
                Text("1").fontWeight(.semibold)
                Spacer()
                Text("2").fontWeight(.semibold)
                Spacer()
                Text("3").fontWeight(.semibold)
            }
        }
        .padding(16)
        .onChange(of: level) { _ in
            // 保留当前旋转的实际角度(取360的余数),避免数值无限累加
            let currentAngle = rotation.truncatingRemainder(dividingBy: 360)
            rotation = currentAngle
            // 触发新的旋转动画
            withAnimation {
                rotation += 360
            }
        }
    }
}

关键改动说明:

  • 移除.id(level),防止视图被销毁重建,保留当前旋转状态
  • 计算当前旋转角度的余数,将rotation重置为该值,避免数值持续增大
  • 用withAnimation触发新动画,新动画基于新的level值计算时长,从当前角度无缝开始旋转

方案二:Timer手动驱动旋转(更灵活的速度控制)

通过Timer实时更新旋转角度,直接响应滑块值变化,完全避免动画重置问题:

struct ContentView: View {
    @State private var level: Double = 0
    @State private var rotation: Double = 0
    // 每0.01秒触发一次更新,保证旋转流畅
    private let updateTimer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()
    
    var body: some View {
        VStack(spacing: 16) {
            Rectangle().fill(.red)
                .frame(width: 100, height: 100)
                .rotationEffect(Angle(degrees: rotation))
            
            Spacer().frame(height: 12)
            Slider(value: $level, in: 0...3, step: 1)
            HStack {
                Text("0").fontWeight(.semibold)
                Spacer()
                Text("1").fontWeight(.semibold)
                Spacer()
                Text("2").fontWeight(.semibold)
                Spacer()
                Text("3").fontWeight(.semibold)
            }
        }
        .padding(16)
        .onReceive(updateTimer) { _ in
            guard level > 0 else { return }
            // 按滑块值计算每秒旋转角度:对应原逻辑中2秒转360度的速度比例
            rotation += level * 1.8
        }
    }
}

关键改动说明:

  • 用Timer实时驱动rotation值更新,速度直接由level控制
  • 无需动画修饰符,旋转状态持续累加,滑块切换时速度平滑过渡
  • 避免了动画系统重置的问题,适合需要实时调整速度的场景

内容的提问来源于stack exchange,提问作者duckSern1108

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:13:09