07-19-2023, 12:35 AM
My view is determined by state stored in a `ViewModel`. Sometimes the view might call a function on its `ViewModel`, causing an asynchronous state change.
How can I animate the effect of that state change in the `View`?
Here's a contrived example, where the call to `viewModel.change()` will cause the view to change colour.
- Expected behaviour: slow dissolve from blue to red.
- Actual behaviour: immediate change from blue to red.
```swift
class ViewModel: ObservableObject {
@Published var color: UIColor = .blue
func change() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.color = .red
}
}
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
Color(viewModel.color).onAppear {
withAnimation(.easeInOut(duration: 1.0)) {
self.viewModel.change()
}
}
}
}
```
If I remove the `ViewModel` and store the state in the view itself, everything works as expected. That's not a great solution, however, because I want to encapsulate state in the `ViewModel`.
```swift
struct ContentView: View {
@State var color: UIColor = .blue
var body: some View {
Color(color).onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
withAnimation(.easeInOut(duration: 1.0)) {
self.color = .red
}
}
}
}
}
```
How can I animate the effect of that state change in the `View`?
Here's a contrived example, where the call to `viewModel.change()` will cause the view to change colour.
- Expected behaviour: slow dissolve from blue to red.
- Actual behaviour: immediate change from blue to red.
```swift
class ViewModel: ObservableObject {
@Published var color: UIColor = .blue
func change() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.color = .red
}
}
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
Color(viewModel.color).onAppear {
withAnimation(.easeInOut(duration: 1.0)) {
self.viewModel.change()
}
}
}
}
```
If I remove the `ViewModel` and store the state in the view itself, everything works as expected. That's not a great solution, however, because I want to encapsulate state in the `ViewModel`.
```swift
struct ContentView: View {
@State var color: UIColor = .blue
var body: some View {
Color(color).onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
withAnimation(.easeInOut(duration: 1.0)) {
self.color = .red
}
}
}
}
}
```