I have a SwiftUI view that is swapping out certain controls depending on state. I'm trying to use MVVM, so most/all of my logic has been pushed off to a view model. I have found that when doing a complex action that modifies a @Published var
on the view model, the View
will not animate.
Here's an example where a 1.0s timer in the view model simulates other work being done before changing the @Published var
value:
struct ContentView: View {
@State var showCircle = true
@ObservedObject var viewModel = ViewModel()
var body: some View {
VStack {
VStack {
if showCircle {
Circle().frame(width: 100, height: 100)
}
Button(action: {
withAnimation {
self.showCircle.toggle()
}
}) {
Text("With State Variable")
}
}
VStack {
if viewModel.showCircle {
Circle().frame(width: 100, height: 100)
}
Button(action: {
withAnimation {
self.viewModel.toggle()
}
}) {
Text("With ViewModel Observation")
}
}
}
}
class ViewModel: ObservableObject {
@Published var showCircle = true
public func toggle() {
// Do some amount of work here. The Time is just to simulate work being done that may not complete immediately.
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { [weak self] _ in
self?.showCircle.toggle()
}
}
}
In the case of view model workflow your withAnimation
does nothing, because not state is changed during this case (it is just a function call), only timer is scheduled, so you'd rather need it as
Button(action: {
self.viewModel.toggle() // removed from here
}) {
Text("With ViewModel Observation")
}
...
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { [weak self] _ in
withAnimation { // << added here
self?.showCircle.toggle()
}
}
However I would rather recommend to rethink view design... like
VStack {
if showCircle2 { // same declaration as showCircle
Circle().frame(width: 100, height: 100)
}
Button(action: {
self.viewModel.toggle()
}) {
Text("With ViewModel Observation")
}
.onReceive(viewModel.$showCircle) { value in
withAnimation {
self.showCircle2 = value
}
}
}
Tested with Xcode 11.2 / iOS 13.2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With