如何在 @Observable 属性更改时执行 SwiftUI 动画

问题描述 投票:0回答:1

我在下面的代码片段中将正方形动画化为圆形。我的视图观察

isCircle
属性来确定是绘制圆形还是方形。
MyData#doSomethingExpensive
方法旨在模拟一个长时间运行的任务,该任务完成后会触发 UI 进行动画处理(在本例中将正方形动画化为圆形)。

这实际上按预期工作,但我的

withAnimation
UI 模型中有一个
@Observable
调用。如果可能的话,我宁愿在视图内有
withAnimation
。我还想继续使用
@Observable
API,而不是切换回
ObservableObject
一致性。有没有办法重构它,以便视图能够使用与我在这里相同的动画来响应
isCircle
中的变化:

import SwiftUI

@Observable
final class MyData {
    var isCircle = false
    func doSomethingExpensive() {
        Task {
            try await Task.sleep(for: .milliseconds(Int.random(in: 300...800)))
            withAnimation(.smooth(duration: 1.5)) {
                self.isCircle.toggle()
            }
        }
    }
}

struct ContentView: View {
    let 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") {
                myData.doSomethingExpensive()
            }
        }
    }
}
animation swiftui observable
1个回答
0
投票

一种方法是,您可以将

Task{...}
移动到视图中,例如:

@Observable
final class MyData {
    var isCircle = false
    
    func doSomethingExpensive() async throws {
        try await Task.sleep(for: .milliseconds(Int.random(in: 300...800))) // <--- here
    }
}

struct ContentView: View {
   let 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 { // <--- here
                    try await myData.doSomethingExpensive()
                    withAnimation(.smooth(duration: 1.5)) {
                        myData.isCircle.toggle()
                    }
                }
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.