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

动画@State变量时Canvas未更新的问题及解决方案咨询

解决SwiftUI Canvas在动画过程中无法获取@State变量实时值的问题

问题原因

Canvas的渲染闭包默认仅在视图初始化或依赖变量发生实质性最终变更时执行,不会自动响应SwiftUI动画过程中的插值计算。当你用withAnimation修改rotationAngle时,Canvas只会在动画启动时获取最终目标值(0.0),而非动画过程中逐帧变化的中间插值,导致无法打印实时值。

解决方案

方案1:利用Canvas的updates参数指定动画依赖

通过Canvas的updates参数明确追踪rotationAngle,并绑定对应动画类型,让Canvas在动画每一帧都重新渲染并获取实时插值:

@State private var rotationAngle: Double = 90.0

HStack {
    // 指定updates依赖rotationAngle,并匹配动画类型
    Canvas(updates: rotationAngle, animation: .easeIn(duration: 2)) { context, size in
        print(rotationAngle) // 现在会打印动画过程中的实时中间值
    }
}
.onTapGesture {
    withAnimation(.easeIn(duration: 2)) {
        rotationAngle = 0.0
    }
}

方案2:自定义AnimatableModifier监听动画插值

通过自定义AnimatableModifier来捕获动画过程中的逐帧值,再传递给Canvas使用:

// 自定义可动画修饰符,用于捕获插值
struct RotationAnimatableModifier: AnimatableModifier {
    var angle: Double
    
    // 动画驱动的数据源
    var animatableData: Double {
        get { angle }
        set { angle = newValue }
    }
    
    func body(content: Content) -> some View {
        content
            // 监听插值变化,可直接在Canvas中使用angle值
            .onChange(of: angle) { currentAngle in
                print(currentAngle) // 实时打印动画中间值
            }
    }
}

// 使用示例
@State private var rotationAngle: Double = 90.0

HStack {
    Canvas() { context, size in
        // 在这里可以直接使用rotationAngle的实时插值
        context.rotate(by: .degrees(rotationAngle))
        // 绘制内容...
    }
    .modifier(RotationAnimatableModifier(angle: rotationAngle))
}
.onTapGesture {
    withAnimation(.easeIn(duration: 2)) {
        rotationAngle = 0.0
    }
}

总结

两种方案的核心都是让SwiftUI明确告知Canvas需要响应动画过程中的插值变化,而非仅依赖状态变量的最终变更。选择哪种方案取决于你的具体场景:如果只是需要在Canvas内部获取实时值,方案1更简洁;如果需要在多个视图间共享动画插值逻辑,方案2更灵活。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 20:40:21