Quentin C
Quentin C

Reputation: 382

Initialize @State property with another @State property value in SwiftUI

I'm trying to get progress value of a progress bar based on another value. Both of these variables (waterQuantity and progress) are in property wrappers @State

This is my code :

struct CircularProgressBar: View {
@State var waterQuantity: Int
@State var progress: Float = (1 + (Float(waterQuantity)/Float(1500))) * 100

var body: some View {
    ZStack {
        Circle()
            .foregroundColor(.white)
            .padding(25)
            .overlay(
                Circle()
                    .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                    .stroke(style: StrokeStyle(lineWidth: 25
                        , lineCap: .round, lineJoin: .round))
                    .foregroundColor(Color.blue)
                    .rotationEffect(Angle(degrees: 270.0))
                    .animation(.linear)
                    .padding(50)
        )
        
        VStack {
            Text(String(format: "%.0i mL", 500))
                .font(.largeTitle)
                .bold()
                .foregroundColor(Color("bgStart"))
            Text("1500 mL")
                .foregroundColor(.gray)
        }
    }
}

As you can see, I cannot initialise progress with another variable that has not been initialized yet. I tried passing values with init() and mutating func, but none of these solutions worked for me 😕

Upvotes: 3

Views: 1649

Answers (3)

Paul Mayer
Paul Mayer

Reputation: 225

Since progress is dependent on the waterQuantity passed into the view, I would suggest performing this computation within the init function. And then initialing progress with a new initial state value.

@State private var waterQuantity: Int
@State private var progress: Float = 0.0

init(waterQuantity: Int){
    self._waterQuantity = State(initialValue: waterQuantity)
    self._progress = State(initialValue: (1 + (Float(waterQuantity)/Float(1500))) * 100)
}

But since it doesn't look like your using waterQuantity within the body of the View. Then it probably doesn't need to have a @State annotation wrapper, and the code could look something like this instead:

private var waterQuantity: Int
@State private var progress: Float = 0.0

init(waterQuantity: Int){
    self.waterQuantity = waterQuantity
    self._progress = State(initialValue: (1 + (Float(waterQuantity)/Float(1500))) * 100)
}

Upvotes: 0

Shehata Gamal
Shehata Gamal

Reputation: 100541

You may not need to make this

@State var progress: Float = Float(waterQuantity)/Float(1500)

a property just leave only waterQuantity and copy paste that code inside the body of view and it'll be refreshed when waterQuantity is changed

Upvotes: 1

raynok
raynok

Reputation: 203

You should change progress to a computed property that doesn't store any value, but rather calculates it's value dynamically based on the value of waterQuantity:

var progress: Float {
    Float(waterQuantity)/Float(1500)
}

Now when waterQuantity is being updated, your view will still be redrawn because waterQuantity is used inside this computed property, which is in turn being used in your view.

Upvotes: 5

Related Questions