前言:
百分比圆环几乎是所有项目,中都会有的。针对于下面的Demo,我们采取双圆的形式,进行百分比圆环的案例分析,并且封装后,以方便备用。
案例展示
在这当中,有以下几个难点,需要我们清楚:
- 1.画圆弧利用的是贝塞尔曲线,我们必须清楚显示圆环和辅助圆环的起点角度和终点角度。
- 2.显示圆环和辅助圆环的起点相同,终点不同
- 3.显示圆环和辅助圆环重合(半径相同,位置相同),显示圆环的终点小于等于辅助圆环的终点
必须理解一下三幅图
第一幅图
第二幅图
通过上图,我们可以这样想,终点的弧度点 - 起点弧度点 = 整个圆弧的弧度 ,整个圆弧的弧度,我们可以把它看成0%~100%这样的百分比,例如:在用20%乘以整个圆弧的弧度这个就说明 ,在整个弧度中占有20%是多少。求出来之后在加上起点,就是显示圆的终点。
第三幅图
通过上幅图,我们要知道起点和终点是怎么平行在一条线上。
代码示例
ZYCircle.h
#import <UIKit/UIKit.h>
@interface ZYCircle : UIView
//起点 角度
@property(nonatomic) CGFloat startAngle;
//终点 角度
@property(nonatomic)CGFloat endInnerAngle;
//线宽
@property(nonatomic)CGFloat lineWith;
//百分比数字
@property (nonatomic)CGFloat percentage;
//基准圆环颜色
@property(nonatomic,strong)UIColor *unfillColor;
//显示圆环颜色
@property(nonatomic,strong)UIColor *fillColor;
//中心数据显示标签
@property (nonatomic ,strong)UILabel *centerLable;
- (instancetype) initWithFrame:(CGRect)frame;
@end
ZYCircle.m
#import "ZYCircle.h"
#define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/ 180)
@interface ZYCircle ()
@property(nonatomic) CGPoint CGPoinCerter;
@property(nonatomic) CGFloat endAngle;
@property(nonatomic) BOOL clockwise;
@end
@implementation ZYCircle
{
CGFloat _radius;
}
-(instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.lineWith = 10.0;
self.fillColor = [UIColor greenColor];
self.unfillColor = [UIColor lightGrayColor];
self.clockwise = YES;
self.backgroundColor = [UIColor clearColor];
self.percentage = 0;
self.startAngle = 180;
self.endAngle = 360;
}
return self;
}
#pragma mark setMethod
/**
* 画图函数
*
* @param rect rect description
*/
-(void)drawRect:(CGRect)rect{
[self initData];
[self drawMiddlecircle];
[self drawOutCCircle];
}
-(void)initData
{
>
//中心标签设置
CGFloat center =MIN(self.bounds.size.height/2, self.bounds.size.width/2);
self.CGPoinCerter = CGPointMake(center, center);
self.centerLable = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 2*center, 2*center)];
self.centerLable.textAlignment=NSTextAlignmentCenter;
self.centerLable.backgroundColor=[UIColor clearColor];
self.centerLable.adjustsFontSizeToFitWidth = YES;
self.centerLable.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.contentMode = UIViewContentModeRedraw;
[self addSubview: self.centerLable];
//半径计算
_radius = MIN(self.bounds.size.height/2-self.lineWith/2, self.bounds.size.width/2-self.lineWith/2);
self.centerLable.font = [UIFont systemFontOfSize:_radius/3];
self.centerLable.text = [NSString stringWithFormat:@"%.1lf%%",self.percentage*100];
//起点与终点坐标
self.endInnerAngle = DEGREES_TO_RADIANS(self.endInnerAngle);
self.startAngle = DEGREES_TO_RADIANS(self.startAngle);
self.endAngle = self.percentage*(self.endInnerAngle - self.startAngle) + self.startAngle;
//0%标签
UILabel *zeroPercentLable = [[UILabel alloc]init];
zeroPercentLable.text = [NSString stringWithFormat:@"0%%"];
CGFloat zeroPercentLableX =_radius + _radius*cos(self.startAngle);
CGFloat zeroPercentLableY = _radius*sin(self.startAngle)+(self.startAngle>DEGREES_TO_RADIANS(180)?-_radius:_radius);
zeroPercentLable.frame = CGRectMake(zeroPercentLableX, zeroPercentLableY+self.lineWith, 2.1*_radius/7.5 + 15, 25);
zeroPercentLable.textAlignment = NSTextAlignmentCenter;
zeroPercentLable.font = [UIFont boldSystemFontOfSize:_radius/7.5 ];
zeroPercentLable.textColor = [UIColor orangeColor];
[self addSubview:zeroPercentLable];
//100%标签
UILabel *hundredPercentLable = [[UILabel alloc]init];
hundredPercentLable.text = [NSString stringWithFormat:@"100%%"];
CGFloat hundredPercentLableX =_radius + _radius*cos(self.endInnerAngle)-8;
CGFloat hundredPercentLableY = _radius*sin(self.endInnerAngle)+(self.endInnerAngle<DEGREES_TO_RADIANS(180)?-_radius:_radius);
hundredPercentLable.frame = CGRectMake(hundredPercentLableX, hundredPercentLableY+self.lineWith, 2.9*_radius/7.5 + 15, 25);
hundredPercentLable.textAlignment = NSTextAlignmentCenter;
hundredPercentLable.font = [UIFont boldSystemFontOfSize:_radius/7.5 ];
hundredPercentLable.textColor = [UIColor orangeColor];
[self addSubview:hundredPercentLable];
}
#pragma mark - 利用layer的 strokeEnd、strokeStart和lineWidth 属性添加CA动画
- (void)addAnimationOneOnLayer:(CAShapeLayer *)layer duration:(CFTimeInterval)duration
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.fromValue = @(0);
animation.toValue = @(1);
animation.duration = duration;
[layer addAnimation:animation forKey:nil];
}
/**
* 显示圆环
*/
-(void )drawOutCCircle{
UIBezierPath *bPath = [UIBezierPath bezierPathWithArcCenter:self.CGPoinCerter radius:_radius startAngle:self.startAngle endAngle:self.endAngle clockwise:self.clockwise];
>
CAShapeLayer *layer = [CAShapeLayer layer];
layer.lineWidth = self.lineWith;
layer.lineCap = kCALineCapRound;
layer.lineJoin = kCALineJoinRound;
layer.strokeColor = self.fillColor.CGColor;
layer.fillColor = nil;
layer.path = bPath.CGPath;
[self.layer addSublayer:layer];
>
[self addAnimationOneOnLayer:layer duration:1.0];
}
/**
* 辅助圆环
*/
-(void)drawMiddlecircle{
UIBezierPath *cPath = [UIBezierPath bezierPathWithArcCenter:self.CGPoinCerter radius:_radius startAngle:self.startAngle endAngle:self.endInnerAngle clockwise:self.clockwise];
cPath.lineWidth=self.lineWith;
cPath.lineCapStyle = kCGLineCapRound;
cPath.lineJoinStyle = kCGLineJoinRound;
UIColor *color = self.unfillColor;
[color setStroke];
[cPath stroke];
}
用法
- (void)setCircle{
ZYCircle *circle = [[ZYCircle alloc] initWithFrame:CGRectMake(30, 20,SCREEN_WIDTH-60 , SCREEN_WIDTH-60)];
circle.percentage = 0.23; //百分比数值
circle.lineWith = 30; //线宽
circle.fillColor = [UIColor redColor]; //填充颜色
circle.unfillColor = [UIColor lightGrayColor]; //未填充颜色
circle.startAngle = 150; //百分百的圆环起点
circle.endInnerAngle = 390; //百分百的圆环终点
// circle.centerLable.text = @"111"; //中心标签的显示数值,默认为百分数
[self.displayView addSubview:circle];
}
#pragma mark - 点击方法
- (IBAction)百分比圆环:(id)sender {
[self setCircle];
}