Want to make a gauge view with indicate arrow and over gauge view display circle which indicate progress

97 Views Asked by At

gauge view with arrow and over gauge view white circle

As per the image, Arrow-based works but now how to add one more white circle over gauge View and move the same as a white arrow.

Click here for Project

1

There are 1 best solutions below

7
MatBuompy On BEST ANSWER

First of all, to reproduce the Indicator of the gauge I would suggest you to use a Shape like this one:

struct IndicatorShape: Shape {
    
    func path(in rect: CGRect) -> Path {
        return Path { path in
            let width = rect.width
            let height = rect.height
            
            path.move(to: CGPoint(x: width / 2, y: 0))
            path.addLine(to: CGPoint(x: 0, y: height))
            path.addLine(to: CGPoint(x: width, y: height))
        }
    }
    
}

And then use it in your code as any other View. To add a Circle over your indicator you could use a simple overlay. Also, you need a masking effect to show the advancement of your gauge. It's a bit complicated and require some fine tuning... Here's the code:

struct MeterReadiness : View {
//speedometerBgColor
let colors = [Color.red,Color.yellow,Color.green,Color.blue]
@State var progress : CGFloat = 0.0

var body: some View{
    
    GeometryReader {
        let size = $0.size
        
        
        ZStack{
            
            Circle()
                .trim(from: 0.0, to: 0.5)
                .stroke(Color.red, lineWidth: 10)
                .frame(width: 280, height: 280)
            
            
            Circle()
                .trim(from: 0, to: self.setProgress())
                .stroke(AngularGradient(gradient: .init(colors: self.colors), center: .center, angle: .init(degrees: 180)), lineWidth: 10)
                .frame(width: 280, height: 280)
            
            ZStack{
                
                Circle()
                    .trim(from: 0.0, to: 0.5)
                    .stroke(Color.blue, lineWidth: 10)
                    .frame(width: 280, height: 280)
                
                
                Circle()
                    .trim(from: 0, to: self.setProgress())
                    .stroke(AngularGradient(gradient: .init(colors: self.colors), center: .center, angle: .init(degrees: 180)), lineWidth: 10)
                    .frame(width: 280, height: 280)
                
            }
            /// Mask the red gauge with the blue one
            .mask {
                /// To make the blue advance
                Circle()
                    .trim(from: 0, to: (progress / 2) + 0.002)
                    .stroke(.white, lineWidth: 40)
            }
            
        }
        .rotationEffect(.init(degrees: 180))
        .overlay {
            /// Custom Indicator
            IndicatorShape()
                .fill(.black)
                .overlay(alignment: .bottom) {
                    /// Circle at the base of the Indicator
                    Circle()
                        .fill(.purple)
                        .frame(width: 30, height: 30)
                        .offset(y: 10)
                } //: Overlay Indicator Bottom Dot
                .frame(width: 25, height: 110)
                .padding(.top, 40)
                .offset(y: -5)
                .overlay(alignment: .top) {
                    /// Here is the Circle above the Indicator
                    Circle()
                        .fill(.white)
                        .frame(width: 20, height: 20)
                        .offset(y: 0)
                        .shadow(radius: 1)
                }
            /// These two lines are to make the Indicator and the Circle move
                .rotationEffect(.degrees(-90), anchor: .bottom)
                .rotationEffect(.degrees(progress * 180), anchor: .bottom)
                .offset(y: -75)
        } //: Overlay Indicator
        .frame(width: size.width, height: size.height, alignment: .center)
        
    }
    .padding(.bottom, -140)
    .onAppear(perform: {
        withAnimation(Animation.default.speed(0.1)){
            self.progress = 1
        }
    })
    .frame(maxHeight: .infinity, alignment: .center)
    
}

In order for this to work I had to set the progress to be in the 0-1 range. You can easily convert that to show 0-100. You may need to adjust the offset position of the circle of course and make any other adjustment you need. Here's the result:

Gauge with masking effect

Let me know if this worked for you!