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)
}
}
}
}