Aligning objects in ZStack

Viewed 139

Curernt Interface

The white bar is supposed to be aligned at the left of the darker bar. I've tried using spacers, or changing the alignment of the individual objects but nothing works. This is my code:

VStack {
      
    HStack {
                
        Text("Calories eaten today:")
            .foregroundColor(.white)
            .fontWeight(.semibold)
                
        Spacer(minLength: 100)
                
        HStack {
            ZStack(alignment: .leading) {
                        
                Capsule()
                    .rotation(.degrees(90))
                    .frame(width: 20, height: CGFloat((calorieGoal/proportion)))
                    .foregroundColor(.black)
                    .opacity(0.2)

                Capsule()
                    .rotation(.degrees(90))
                    .frame(width: 20, height: CGFloat((Swift.min((eatendatabase.dayNutrients[0]/proportion), 180))), alignment: .leading)
            }
                    
            Spacer(minLength: 20)
                    
            Text("\(String(format: "%.0f", eatendatabase.dayNutrients[0]))")
                .font(.caption)
                .foregroundColor(.white)
                .frame(alignment: .trailing)
                    
        }
            Spacer()
    }
}
.padding(.horizontal, 30)


  
1 Answers

As calorieGoal, proportional, and eatendatabase.dayNutrients were not provided as values, I have used the following constant and variable to keep track of the capsule's widths, which I will denote in the code as the "progress bar":

let MAX_WIDTH: CGFloat = 100.0
let currentProgress: CGFloat = 40.0

With that in mind, first you should consider moving the calorie count label ("832") outside of the HStack containing the progress bar. Second, you nested both the background and foreground capsules forming the progress bars in a ZStack. We can take the foreground capsule and align it to the left by nesting it in an HStack with a Spacer:

HStack {

    Capsule()
        .rotation(.degrees(90))
        .frame(width: 20.0, height: currentProgress /*This is the progress width of the bar, out of 100*/)
    
    Spacer()
    
}

Of course, we need to set the width of the HStack to the width of the background capsule, so that the foreground capsule aligns properly with the leading edge of the background capsule:

HStack {

    ...

}.frame(width: MAX_WIDTH)

Overall, here is a possible solution to your issue:

VStack {
      
    HStack {
                
        Text("Calories eaten today:")
            .foregroundColor(.white)
            .fontWeight(.semibold)
            // Made this font smaller for the preview
            .font(.footnote)
           
        // Add auto space between the label and the progress bar
        Spacer()
             
        // Separate the capsule progress bar from the calorie count
        ZStack {
                    
            Capsule()
                .rotation(.degrees(90))
                .frame(width: 20.0, height: MAX_WIDTH /*This is the max width of the bar*/)
                .foregroundColor(.black)
                .opacity(0.2)
            
            // Nesting the progress Capsule in an HStack so we can align it to the left
            HStack {

                Capsule()
                    .rotation(.degrees(90))
                    .frame(width: 20.0, height: currentProgress /*This is the progress width of the bar, out of 100*/)
                
                // Adding a Spacer will force the Capsule to the left when it is in an HStack
                Spacer()
                
            }
            // Set the frame width of the HStack to the same width as the background capsule
            .frame(width: MAX_WIDTH)
            
        }
        
        // Add auto space between the progress bar and the calorie count
        Spacer()
        
        // The calorie count text, nested in an HStack with the label and the progress bar
        Text("832")
            .font(.caption)
            .foregroundColor(.white)
            .frame(alignment: .trailing)
    }
}
.padding(.horizontal, 30)
// Added a gray background for the preview
.background(Color.gray)

And it would look like this:

The preview.

Related