I just started with Swift a few days ago, so sorry if this question is kinda simple but I was not able to find a matching answer on Google for it.
I want to implement a number that is "slowly" running down on a change. I want this number always to reach it's goal within a second no matter if it runs from 1000 to 100 or 110 to 100. But as of now, the UI always just takes the first change and not the following changes (I see different print outputs with the proper values but the actual UI does not update).
This is how my model currently looks like:
This is my control which displays the "life points":
So what did I miss to let the UI update to each change? I think I also messed up the Text(self.player.name) because this one does also not update on a change from another View. But for that problem I still have a few ideas how I can fix it not like with the async update stuff..
I want to implement a number that is "slowly" running down on a change. I want this number always to reach it's goal within a second no matter if it runs from 1000 to 100 or 110 to 100. But as of now, the UI always just takes the first change and not the following changes (I see different print outputs with the proper values but the actual UI does not update).
This is how my model currently looks like:
Code Block import SwiftUI class Player: Identifiable { let id = UUID() @Published var name: String @Published var maximumLifePoints: Int @Published var currentLifePoints: Int { didSet { currentProgress = 1.0 / Float(maximumLifePoints) * Float(currentLifePoints) } } @Published var currentProgress: Float = 1 init(name: String, startLifePoints: Int) { self.name = name self.maximumLifePoints = startLifePoints self.currentLifePoints = startLifePoints } func setCurrentLifePoints(lifePoints: Int) { let difference = currentLifePoints - lifePoints let differencePerStep = difference / 100 print("Diffrence: \(difference)") print("Diffrence step: \(differencePerStep)") let timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { timer in self.currentLifePoints -= differencePerStep print("Current life points: \(self.currentLifePoints)") } timer.fire() DispatchQueue.main.asyncAfter(deadline: .now() + 0.99) { timer.invalidate() self.currentLifePoints = lifePoints print("Final life points: \(self.currentLifePoints)") } } }
This is my control which displays the "life points":
Code Block import SwiftUI struct LiveCounter: View { @State var player: Player var body: some View { GeometryReader { g in VStack (alignment: .center, spacing: 25.0) { ZStack { Circle() .fill(Color.offColor) .frame(width: self.circleSize(g.size), height: self.circleSize(g.size), alignment: .center) ProgressBar(currentValue: self.$player.currentProgress) .frame(width: self.circleSize(g.size), height: self.circleSize(g.size), alignment: .center) VStack (spacing: -4) { Text(self.player.name) .font(.system(size: g.size.height > g.size.width ? g.size.width * 0.04 : g.size.height * 0.04)) .fontWeight(.bold) .foregroundColor(Color.textDefaultColor) Text("\(self.player.currentLifePoints.formattedWithSeparator)") .font(.system(size: g.size.height > g.size.width ? g.size.width * 0.1 : g.size.height * 0.1)) .fontWeight(.black) .foregroundColor(Color.textDefaultColor) //Spacing to have life points still in center Text(" ") .font(.system(size: g.size.height > g.size.width ? g.size.width * 0.04 : g.size.height * 0.04)) .fontWeight(.bold) } } } } } private func circleSize(_ size: CGSize) -> CGFloat? { return size.height > size.width ? size.width * 0.5 : size.height * 0.5 } }
So what did I miss to let the UI update to each change? I think I also messed up the Text(self.player.name) because this one does also not update on a change from another View. But for that problem I still have a few ideas how I can fix it not like with the async update stuff..
@Published vars work well with SwiftUI when they are defined in an ObservableObject, and used within an @ObservedObject property.
Use @ObservedObject instead of @State. (You need to fix some other parts according to this change.)
Use @ObservedObject instead of @State. (You need to fix some other parts according to this change.)
Code Block @ObservedObject var player: Player