Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to bind a Float value from a model to a @Binding:Float property in a SwiftUI View

I have a Circular ProgressBar View that takes a @Binding var progress: Float property as its progress value, what I would like to be able to do is pass the var progress: Float value from the Task objects respectably in the List. I tried assigning the progress = task.progress the value from the Task objects to a @State property within the ContentView but of course that cannot be done inside a View (see commented code line below).

How can I pass the progress values from each Task to the ProgressBar view respectably?

Task Model:

class Task:Identifiable{
    var name = ""
    var progress: Float = 0.0
    
    init(name:String, progress:Float){
        self.name = name
        self.progress = progress
    }
}

Content View

var tasks = [Task(name: "Ketchen Floors", progress: 0.5),
            Task(name: "Install Windows", progress: 0.75)]

struct ContentView: View {
    @State var progress:Float = 0.15
    
    var body: some View {
        List {
            ForEach(tasks) { task in
                // outputs error: Type '()' cannot conform to 'View'
                // progress = task.progress 
                HStack{
                    Text(task.name)
                    // here $progress value shoud come from task.progress
                    ProgressBar(progress: $progress)
                }
            }
        }
    }
}

ProgressBar View

struct ProgressBar: View {
    @Binding var progress: Float
    
    var body: some View {
        ZStack {
            Circle()
                .stroke(lineWidth:5.0)
                .opacity(0.3)
                .foregroundColor(Color.orange)
            
            Circle()
                .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                .stroke(style: StrokeStyle(lineWidth: 5.0, lineCap: .round, lineJoin: .round))
                .foregroundColor(Color.orange)
                .rotationEffect(Angle(degrees: 270.0))
                .animation(.linear, value: progress)

            VStack{
                Text(String(format: "%.0f %%", min(self.progress, 1.0)*100.0))
                    .font(.caption2)
            }
        }
    }
}

Screen

As you can see, every item shows the initial 15% progress value, no surprise. Again, what I want is to be able to use the value from each Task respectably, Ketchen Floors at 50% and Install Windows at 75%.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

enter image description here

>Solution :

First, add your array inside ContentView and make it @State

After that, you can directly bind var by task.

struct ContentView: View {
    @State var progress:Float = 0.15
    
    @State var tasks = [Task(name: "Ketchen Floors", progress: 0.5),
                 Task(name: "Install Windows", progress: 0.75)] // <---- Here
    
    var body: some View {
        List {
            ForEach($tasks) { $task in // <---- Here
                // outputs error: Type '()' cannot conform to 'View'
                // progress = task.progress
                HStack{
                    Text(task.name)
                    // here $progress value shoud come from task.progress
                    ProgressBar(progress: $task.progress) // <---- Here
                }
            }
        }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading