I want to draw this two rectangles in SwiftUI

387 views Asked by At

I'm struggling on creating two vertical bars with lines and dash box. I would like to receive some suggestion on how to do this.

This is what I'm aiming to do:

image

Currently this is my code.

import SwiftUI

struct LoadManagementItemBarView: View {
    
    let isLeft: Bool
    let userWeight: Float
    @State var progress: CGFloat
    
    var body: some View {
            ZStack(alignment: .bottom) {
                Rectangle()
                    .fill(Color.white)
                    .frame(width: 32, height: 490)
                
                Rectangle()
                    .fill(Color.positiveStappone)
                    .frame(width: 32, height: progress)
                
                VStack {
                    HStack(alignment: .center) {

                        if isLeft {
                            Text("\(String(format: "%.0f", userWeight)) kg")
                        }
                        
                        Rectangle()
                            .frame(width: 38, height: 1)
                        
                        if !isLeft {
                            Text("\(String(format: "%.0f", userWeight)) kg")
                        }
                    }
                    .offset(y: CGFloat(userWeight))
                    
                    Rectangle()
                        .strokeBorder(style: StrokeStyle(lineWidth: 1, dash: [10]))
                        .frame(width: 32, height: 188)
                        .offset(x: isLeft ? 24 : -23, y: -76)
                    
                    HStack(alignment: .center) {

                        if isLeft {
                            Text(" 0 kg")
                        }
                        
                        Rectangle()
                            .frame(width: 38, height: 1)
                        
                        if !isLeft {
                            Text(" 0 kg")
                        }
                    }
                    .offset(y: 11)
                }
                .offset(x: isLeft ? -24 : 23)
            }
            .shadow(color: .gray, radius: 1, x: 1, y: 1)
    }
}

struct LoadManagementItemBarView_Previews: PreviewProvider {
    static var previews: some View {
        LoadManagementItemBarView(
            isLeft: true,
            userWeight: 76,
            progress: 350
        )
    }
}

I tried to use ZStack to fit all of the UI components but I'm struggling with the offset of these component, example to modify it's y offset by just adding a max KG to the property created. I want it to look like in the image below.

2

There are 2 answers

2
mansoor ali On
struct ContentView: View {
var body: some View {
    VStack {
        Spacer()
        HStack {
            Rectangle()
                .frame(width: 5, height: 50)
            Spacer()
            Rectangle()
                .frame(width: 5, height: 50)
        }
        Spacer()
        HStack {
            Rectangle()
                .frame(width: 80, height: 2)
        }
        Spacer()
    }
    .frame(width: 150, height: 100)
    .border(Color.black, style: .dashed)
}

}

0
Benzy Neez On

I would suggest you split the background bar and the marker (the dashed box) into two separate View implementations, then apply the marker as an overlay. Something like:

private var backgroundBar: some View {
    // Implement the background bar here
}

private var marker: some View {
    Rectangle()
        .strokeBorder(
            style: StrokeStyle(
                lineWidth: 1,
                dash: [10]
            )
        )
        // Only the height needs to be specified
        .frame(height: myComputedHeight)

        // Only the y-offset needs to be specified
        .offset(y: myComputedOffset)
}

var body: some View {
    backgroundBar
        .overlay(marker, alignment: .top)
}

For iOS 15+ you probably want to use the new version of the .overlay modifier, the version I've used here has been deprecated.

For the bar scaling, two possible ways to approach would be:

  • either, implement the scaling in another separate View and combine the views using an HStack
  • or, include the scaling in the backgroundBar view and then add appropriate padding (left or right) to the marker.