I'm new to SwiftUI coming from UIKit. I'm trying to achieve the following:
- Given an array of mutable states in a view model that represents current progress to be displayed on a
Circleusingtrim(from:to:) - Loop over each item to render a circle with the current progress and animate changes from the old to the new position
- A view model will periodically update the array that is a @Published value in an ObservableObject.
I setup a demo view that looks like this
@StateObject var demoViewModel: DemoViewModel = DemoViewModel()
var body: some View {
ForEach(demoViewModel.progress, id: \.self) { progress in
Circle()
.trim(from: 0, to: progress.progress)
.stroke(style: StrokeStyle(lineWidth: 15, lineCap: .round))
.foregroundColor(.red)
.frame(width: 100)
.rotationEffect(.degrees(-90))
.animation(.linear(duration: 1), value: demoViewModel.progress)
}
}
and a test view model like this
class DemoViewModel: ObservableObject {
@Published var progress: [Demo] = [.init(progress: 0)]
struct Demo: Hashable {
let progress: Double
}
init() {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
let current = self.progress[0]
if current.progress < 1 {
self.progress[0] = .init(progress: current.progress + 0.1)
}
}
}
}
For the sake of the demo the array only has one item. What I expected was on each iteration a new value is written to the item in the array which triggers the animation to animate to that value. What actually happens is the progress updates, but it jumps to each new value for no animation.