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

SwiftUI @Observable 动画失效:是使用错误还是Apple Bug?

问题描述

我有一个Toggle,原本应该触发视图出现的动画:

  • 使用普通@State时,动画正常工作("Is On"文本会带动画出现):
struct ExampleView_State: View {
    @State var isOn = false
    
    var body: some View {
        Form {
            Section {
                Toggle("Toggle", isOn: $isOn.animation())
            }
            if isOn {
                Section {
                    Text("Is On")
                }
            }
        }
    }
}
  • 但将状态移至由SwiftUI新的@Observable特性控制的外部对象时,动画丢失:
@Observable
class ExampleViewModel_Observation {
    var isOn: Bool = false
}

struct ExampleView_Observation: View {
    @State var viewModel = ExampleViewModel_Observation()
    
    var body: some View {
        Form {
            Section {
                Toggle("Toggle", isOn: $viewModel.isOn.animation())
            }
            if viewModel.isOn {
                Section {
                    Text("Is On")
                }
            }
        }
    }
}
  • 而等效的ObservableObject实现则工作正常:
class ExampleViewModel_ObservableObject: ObservableObject {
    var isOn: Bool = false
}

struct ExampleView_ObservableObject: View {
    @StateObject var viewModel = ExampleViewModel_ObservableObject()
    
    var body: some View {
        Form {
            Section {
                Toggle("Toggle", isOn: $viewModel.isOn.animation())
            }
            if viewModel.isOn {
                Section {
                    Text("Is On")
                }
            }
        }
    }
}

请问我使用@Observable/Swift Observation的方式有误,还是这是Apple的Bug?


问题原因与解决方案

这不是Apple的Bug,是你对@Observable绑定动画的用法存在问题。

@Observable生成的绑定类型与ObservableObject的绑定类型对.animation()的处理逻辑不同,不能直接在绑定路径末尾附加.animation(),可以通过以下两种方式修复:

方式1:给Toggle添加animation修饰符

将动画应用到Toggle本身,而非绑定对象上:

struct ExampleView_Observation: View {
    @State var viewModel = ExampleViewModel_Observation()
    
    var body: some View {
        Form {
            Section {
                Toggle("Toggle", isOn: $viewModel.isOn)
                    .animation(.default, value: viewModel.isOn)
            }
            if viewModel.isOn {
                Section {
                    Text("Is On")
                }
            }
        }
    }
}

方式2:用withAnimation包裹状态修改

在Toggle的动作回调中,手动用withAnimation包裹状态变更操作:

struct ExampleView_Observation: View {
    @State var viewModel = ExampleViewModel_Observation()
    
    var body: some View {
        Form {
            Section {
                Toggle("Toggle", isOn: $viewModel.isOn) { newValue in
                    withAnimation {
                        viewModel.isOn = newValue
                    }
                }
            }
            if viewModel.isOn {
                Section {
                    Text("Is On")
                }
            }
        }
    }
}

为什么ObservableObject可以正常工作?

ObservableObject的绑定($viewModel.isOn)是标准的Binding<Value>类型,会自动把动画关联到状态变化的传播流程中;而@Observable生成的是Observation.Binding<Value>类型,需要显式指定动画的作用位置才能触发视图过渡动画。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 08:52:56