Search code examples
iosobjective-cswiftiphonegauge

how to make a gauge view as in the following image in iOS?


I have looked at the libraries like gaugekit but they does not solve my problem. Are there any other libraries for making gauge view as in the image? If not, then how can I go around about it?

As @DonMag pointed out. I have tried to make the changes in gaugekit by adding a view on top the gauge view....but it does not turns out to be good.

So I am stuck out at making the spaces in between the actual gauge.

https://i.sstatic.net/wiJ1E.jpg


Solution

  • I suggest you create your own custom view, it's not so difficult. Here is how I would do it. I have left out some details for clarity, but you can see in the comments my suggested solutions for that.

    First, create a sub-class of UIVew. We will need one property to keep track of the gauge position. This goes into your .h file.

    @interface GaugeView : UIView
    
    @property (nonatomic) CGFloat knobPosition;
    
    @end
    

    Next, add the implementation. The GaugeView is a view in itself, so it will be used as the container for the other parts we want. I have used awakeFromNib function to do the initialization, so that you can use the class for a UIView in Storyboard. If you prefer, you can do the initialization from an init function also.

    I have not provided code for the knob in the center, but I would suggest you simply create one view with a white disc (or two to make the gray circle) and the labels to hold the texts parts, and beneath that you add an image view with the gray pointer. The pointer can be moved by applying a rotational transform it.

    - (void)awakeFromNib {
        [super awakeFromNib];
    
        // Initialization part could also be placed in init
        [self createSegmentLayers];
    
        // Add knob views to self
        // :
    
        // Start somewhere
        self.knobPosition = 0.7;
    }
    

    Next, create the segments. The actual shapes are not added here, since they will require the size of the view. It is better to defer that to layoutSubviews.

    - (void)createSegmentLayers {
        for (NSInteger segment = 0; segment < 10; ++segment) {
            // Create the shape layer and set fixed properties
            CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    
            // Color can be set differently for each segment
            shapeLayer.strokeColor = [UIColor blueColor].CGColor;
            shapeLayer.lineWidth = 1.0;
    
            [self.layer addSublayer:shapeLayer];
        }
    }
    

    Next, we need to respond to size changes to the view. This is where we create the actual shapes too.

    - (void)layoutSubviews {
        [super layoutSubviews];
    
        // Dynamically create the segment paths and scale them to the current view width
        NSInteger segment = 0;
        for (CAShapeLayer *layer in self.layer.sublayers) {
            layer.frame = self.layer.bounds;
            layer.path = [self createSegmentPath:segment radius:self.bounds.size.width / 2.0].CGPath;
    
            // If we should fill or not depends on the knob position
            // Since the knobPosition's range is 0.0..1.0 we can just multiply by 10
            // and compare to the segment number
            layer.fillColor = segment < (_knobPosition * 10) ? layer.strokeColor : nil;
    
            // Assume we added the segment layers first
            if (++segment >= 10)
                break;
        }
    
        // Move and size knob images
        // :
    }
    

    Then we need the shapes.

    - (UIBezierPath *)createSegmentPath:(NSInteger)segment radius:(CGFloat)radius {
        UIBezierPath *path = [UIBezierPath bezierPath];
    
        // We could also use a table with start and end angles for different segment sizes
        CGFloat startAngle = segment * 21.0 + 180.0 - 12.0;
        CGFloat endAngle = startAngle + 15.0;
    
        // Draw the path, two arcs and two implicit lines
        [path addArcWithCenter:CGPointMake(radius, radius) radius:0.9 * radius startAngle:DEG2RAD(startAngle) endAngle:DEG2RAD(endAngle) clockwise:YES];
        [path addArcWithCenter:CGPointMake(radius, radius) radius:0.75 * radius startAngle:DEG2RAD(endAngle) endAngle:DEG2RAD(startAngle) clockwise:NO];
        [path closePath];
    
        return path;
    }
    

    Finally, we want to respond to changes to the knobPosition property. Calling setNeedsLayout will trigger a call to layoutSubviews.

    // Position is 0.0 .. 1.0
    - (void)setKnobPosition:(CGFloat)knobPosition {
        // Rotate the knob image to point at the right segment
        // self.knobPointerImageView.transform = CGAffineTransformMakeRotation(DEG2RAD(knobPosition * 207.0 + 180.0));
    
        _knobPosition = knobPosition;
        [self setNeedsLayout];
    }
    

    This is what it will look like now. Add the knob, some colors and possibly different sized segments and you are done!

    enter image description here