Learn Courses My Dashboard

Display issue with linear progression bar

I’m trying to make a linear progression bar that will show the progress based on the current value from the goal value. For instance, if my current step count is 7,500 steps and my goal step count is 10,000, I would like the bar to be filled up 75% out of 100% and so forth. I can display the percentage in a Text view but I’m having issues with it being dynamic. I’ve used the trim method on the progress bar based on the value and goal but nothing is changing. Any suggestions will be appreciated!

Here is the Linear Progress View

struct ProgressionStepBar: View {
    
    let value: Int
    let goalValue: Int
    var color1: Color = .mint
    var color2: Color = .green
   
    
    
    var body: some View {
     
        ZStack(alignment: .leading) {
            
            Capsule()
                .fill(Color.black.opacity(0.1))
                .frame(height: 18)
            
            
          
                Capsule()
                    .trim(from: 0, to: CGFloat(self.value) / CGFloat(self.goalValue))
                    .frame(width: 250, height: 18)
                    .background(
                        LinearGradient(gradient: Gradient(colors: [color1, color2]), startPoint: .leading, endPoint: .trailing).clipShape(Capsule())
                    )
                    .foregroundColor(.clear)
        }
    }
}

Here is the view to display the information. I’m using my ViewModel to get the step count


    @StateObject var healthStore = HealthStoreViewModel()
//This is a computed property from the view model to get the current step count. 
 var currentStepCount: Int {
        steps.last?.count ?? 0
    }

VStack {
       Image(systemName: "figure.walk")
                    .font(.largeTitle)
                Text("\(healthStore.currentStepCount) steps")
                HStack {
                    Text("Goal: 10,000 steps")
                        .font(.caption)
                    Spacer()
                    Text("\(healthStore.stepCountPercent)%")
                        .font(.caption)
                }
                ProgressionStepBar(value: healthStore.currentStepCount, goalValue: 10_000)
}

Try this and see how it goes. You need a GeometryReader so that you can have greater control over the object.

struct ProgressionStepBar: View {

    let value: CGFloat
    let goalValue: CGFloat
    var color1: Color = .mint
    var color2: Color = .green

    var body: some View {

        GeometryReader { gr in
            VStack {
                ZStack(alignment: .leading) {
                    Capsule()
                        .fill(Color.black.opacity(0.1))
                        .frame(width: gr.size.width)

                    LinearGradient(gradient: Gradient(colors: [color1, color2]), startPoint: .leading, endPoint: .trailing).clipShape(Capsule())
                        .frame(width: gr.size.width * (value / goalValue))
                }
            }
        }
        .frame(height: 18)
    }
}

struct ProgressionStepBar_Previews: PreviewProvider {
    static var previews: some View {
        ProgressionStepBar(value: 7500, goalValue: 10000)
    }
}

When you use it in another view you can add padding() to it so that the edges are pulled in and the GeometryReader in the ProgressionStepBar adjusts automatically based on the space available.

Hi @KevinJeon6

Try checking this video from youtuber Mike Mikina.