How to dynamically update a SwiftUI View with an @Bindable value

Hi, I have a SwiftUI ProgressBar View that displays the percentage progress based on a percentage-value you enter as a Bindable parameter. The progress percentage-value is calculated by a ReminderHelper class, which takes two Ints as its parameters, totalDays and daysLeft, the values input to the ReminderHelper class come from a Reminder object saved in Core Data.

I'm very confused as to how to structure my code to accomplish such of thing due to the poor understanding of how the SwiftUI/Combine, @Binding, @Published, @State, etc. work.

Based on the code below, what I'm expecting to see is two reminders, Cut the Grass at 20% and Power Wash Siding at 50%. Again, the two Ints that determine the total percentage progress come from the Reminder object saved in Core Data and the actual total percentage result comes from the RemindersHelper class.

Any idea how to accomplish what I describe above?

Model:

This is saved in Core Data.

class Reminder:Identifiable{
    var name = ""
    var totalDays = 0
    var daysLeft = 0
    
    init(name:String, totalDays:Int, daysLeft:Int){
        self.name = name
        self.totalDays = totalDays
        self.daysLeft = daysLeft
    }
}

Helper class

This needs to be in charge of calculating the total percentage that will be passed to the ProgressBar View with the values coming from the Reminder object saved in Core Data.

class ReminderHelper:ObservableObject{
    @Published var percentageLeft: Float = 0.80
    
    func calculatePerentageLeft(daysLeft: Int, totalDays:Int)->Float{
        percentageLeft  = Float(daysLeft / totalDays)
        return percentageLeft
    }
}

Content View:

Here I'm calling the calculatePerentageLeft method to prepare the percentageLeft property before presenting the ProgressBar. Which of course is not working. I see an error:

Static method 'buildBlock' requires that 'Float' conform to 'View'

struct ContentView: View {
    var reminders = [Reminder(name: "Cut the Grass", totalDays: 50, daysLeft: 10),
                Reminder(name: "Power Wash Siding", totalDays: 30, daysLeft: 15)]
    
    @StateObject var reminderModel = ReminderHelper()
    
    var body: some View {
        List {
            ForEach(reminders) { reminder in
                HStack{
                    Text(reminder.name)
                    reminderModel.calculatePerentageLeft(daysLeft: reminder.daysLeft, totalDays: reminder.totalDays)
                    ProgressBar(progress: reminderModel.percentageLeft)
                }
            }
        }
    }
}

ProgressBar View

This is the view in charge of drawing and displaying the percentage value.

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)
            }
        }
    }
}
Answered by fsdolphin in 709491022

I removed all Binding related, changed the Float(daysLeft / totalDays) to Float(dayLeft) / Float(totalDays) and just called the calculatePercentageLeft function directly from the ProgressBar view.

Accepted Answer

I removed all Binding related, changed the Float(daysLeft / totalDays) to Float(dayLeft) / Float(totalDays) and just called the calculatePercentageLeft function directly from the ProgressBar view.

How to dynamically update a SwiftUI View with an @Bindable value
 
 
Q