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

如何在@Observable属性变更时实现SwiftUI动画并重构逻辑

重构方案:将动画逻辑移至SwiftUI视图内

核心思路是把耗时任务执行和UI状态切换+动画触发分离,让MyData只负责处理耗时操作,视图层控制动画的启动时机,同时保留@Observable API的使用。

步骤1:修改MyData,剥离状态修改逻辑

让doSomethingExpensive仅专注于耗时任务,不再直接修改isCircle:

import SwiftUI

@Observable
final class MyData {
    var isCircle = false
    
    // 仅执行耗时操作,不修改UI状态
    func doSomethingExpensive() async throws {
        try await Task.sleep(for: .milliseconds(Int.random(in: 300...800)))
    }
}

步骤2:在视图内触发动画

在ContentView中,点击按钮后先等待耗时任务完成,再通过withAnimation包裹状态切换,将动画逻辑完全移至视图层:

struct ContentView: View {
    @State private var myData = MyData()
    
    var body: some View {
        VStack {
            // 根据状态展示不同形状
            if myData.isCircle {
                Circle().fill(.blue).frame(width: 200)
            } else {
                Rectangle().fill(.red).frame(width: 200, height: 200)
            }
            
            Button("Animate later") {
                Task {
                    // 等待耗时任务完成
                    try await myData.doSomethingExpensive()
                    // 在视图内触发动画并切换状态
                    withAnimation {
                        myData.isCircle.toggle()
                    }
                }
            }
        }
    }
}

另一种可选方案:保留MyData的状态管理,用@Bindable绑定

如果需要MyData仍持有状态,但动画由视图控制,可以使用@Bindable包装@Observable实例:

struct ContentView: View {
    private let myData = MyData()
    @Bindable private var bindableData: MyData
    
    init() {
        self.bindableData = myData
    }
    
    var body: some View {
        VStack {
            if bindableData.isCircle {
                Circle().fill(.blue).frame(width: 200)
            } else {
                Rectangle().fill(.red).frame(width: 200, height: 200)
            }
            
            Button("Animate later") {
                Task {
                    try await myData.doSomethingExpensive()
                    withAnimation {
                        bindableData.isCircle.toggle()
                    }
                }
            }
        }
    }
}

两种方案都能实现原有的动画效果,且完全符合将动画逻辑移至视图内、使用@Observable API的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 14:23:20