iOS developer
iOS developer

Reputation: 17

how Draw a percentage of a circle objective c

i can need layout like same as image but i can not draw like this so any idea about this,

enter image description here

Upvotes: 0

Views: 358

Answers (2)

Rob
Rob

Reputation: 437532

The easiest approach would be to have a view with two subviews, one for the green "percent filled" level, and one for the label for the text. Then you can update the frame for the "percent filled" based upon, obviously, what percent filled you want it. And then apply a circular mask to the whole thing.

For example:

//  CircleLevelView.h
//
//  Created by Robert Ryan on 10/28/17.

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface CircleLevelView : UIView

/// Percent filled
///
/// Value between 0.0 and 1.0.

@property (nonatomic)         IBInspectable CGFloat percent;

/// Text to show up in center of view
///
/// Value between 0.0 and 1.0.

@property (nonatomic, strong) IBInspectable NSString *text;

@end

And

//  CircleLevelView.m
//
//  Created by Robert Ryan on 10/28/17.

#import "CircleLevelView.h"

@interface CircleLevelView()
@property (nonatomic, weak) CAShapeLayer *circleMask;
@property (nonatomic, weak) UILabel *label;
@property (nonatomic, weak) UIView *fillView;

@end

@implementation CircleLevelView

@synthesize percent = _percent;

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];

    [self configure];

    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    [self configure];

    return self;
}

- (instancetype)init {
    return [self initWithFrame:CGRectZero];
}

- (void)configure {
    self.clipsToBounds = true;

    UILabel *fillView = [[UILabel alloc] init];
    fillView.translatesAutoresizingMaskIntoConstraints = false;
    fillView.backgroundColor = [UIColor colorWithRed:169.0 / 255.0
                                               green:208.0 / 255.0
                                                blue:66.0 / 255.0
                                               alpha:1.0];
    [self addSubview:fillView];
    self.fillView = fillView;

    UILabel *label = [[UILabel alloc] init];
    label.translatesAutoresizingMaskIntoConstraints = false;
    label.backgroundColor = [UIColor clearColor];
    label.textColor = [UIColor blackColor];
    label.textAlignment = NSTextAlignmentCenter;
    [self addSubview:label];
    self.label = label;

    [NSLayoutConstraint activateConstraints:@[
        [label.topAnchor constraintEqualToAnchor:self.topAnchor],
        [label.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
        [label.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
        [label.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
        [fillView.topAnchor constraintEqualToAnchor:self.topAnchor],
        [fillView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
        [fillView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
        [fillView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor]
    ]];

    CAShapeLayer *circleMask = [CAShapeLayer layer];
    circleMask.fillColor = [UIColor whiteColor].CGColor;
    circleMask.strokeColor = [UIColor blackColor].CGColor;
    circleMask.lineWidth = 0;
    self.layer.mask = circleMask;
    self.circleMask = circleMask;
}

- (void)layoutSubviews {
    [super layoutSubviews];

    CGPoint center = CGPointMake(self.bounds.origin.x + self.bounds.size.width / 2.0, self.bounds.origin.y + self.bounds.size.height / 2.0);
    CGFloat radius = MIN(self.bounds.size.width, self.bounds.size.height) / 2.0;
    self.circleMask.path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:M_PI * 2.0 clockwise:true].CGPath;

    [self updatePercentFill];
}

- (void)updatePercentFill {
    CGFloat circleHeight = MIN(self.bounds.size.width, self.bounds.size.height);
    CGFloat percentHeight = circleHeight * self.percent;
    self.fillView.frame = CGRectMake(0,
                                     (self.bounds.size.height - circleHeight) / 2 + (circleHeight - percentHeight),
                                     self.bounds.size.width,
                                     circleHeight);
}

// MARK: - Custom Accessor Methods

- (CGFloat)percent {
    return _percent;
}

- (void)setPercent:(CGFloat)percent {
    _percent = percent;

    [self updatePercentFill];
}

- (NSString *)text {
    return self.label.text;
}

- (void)setText:(NSString *)text {
    self.label.text = text;
}

@end

That yields:

enter image description here

Upvotes: 1

CRD
CRD

Reputation: 53000

If you know the chord position you can fill to the chord by setting the clip region and then filling the circle.

To work out the position of the chord to give an area of x% you'll need to do some geometry/trigonometry. Every chord which does not pass through the centre forms and isosceles triangle with the centre, and the two sides of that triangle which are radii delimit a segment of the circle. So the area on one side of a chord which does not pass through the centre is the difference of the area of a triangle and a segment, and you can work out how the chord divides the area or where the chord needs to be to divide the area in a particular ratio.

If that all sounds like gobbledegook try looking up chord geometry and you'll undoubtedly find books/sites with helpful diagrams and formulas.

HTH

Upvotes: 0

Related Questions