iOS - 关于百分比圆环的解读

前言:

百分比圆环几乎是所有项目,中都会有的。针对于下面的Demo,我们采取双圆的形式,进行百分比圆环的案例分析,并且封装后,以方便备用。

案例展示

yuanhuan.gif

在这当中,有以下几个难点,需要我们清楚:

  • 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];
 }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容