前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >绘图-圆环进度条实现详解

绘图-圆环进度条实现详解

作者头像
進无尽
发布2018-09-12 18:28:16
2.1K0
发布2018-09-12 18:28:16
举报
文章被收录于专栏:進无尽的文章進无尽的文章

前言

实现了一款时下比较流行的环状进度动图,以下是源码解析


使用 Core Graphics 和 定时器 实现环形进度动图

圆环进度.gif

核心源码

# 使用  [self setNeedsDisplay];  会触发drawRect 方法达到刷新视图的效果。
//画背景线、填充线、小圆点、文字
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    
    
    #获取图形上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    #设置中心点 半径 起点及终点
    CGFloat maxWidth = self.frame.size.width<self.frame.size.height?self.frame.size.width:self.frame.size.height;
    CGPoint center = CGPointMake(maxWidth/2.0, maxWidth/2.0);
    CGFloat radius = maxWidth/2.0-_strokeWidth/2.0-1;//留出一像素,防止与边界相切的地方被切平
    CGFloat endA = _startAngle + (CircleDegreeToRadian(360) - _reduceValue);//圆终点位置
    CGFloat valueEndA = _startAngle + (CircleDegreeToRadian(360)-_reduceValue)*fakeProgress;  //数值终点位置
    
    #灰色区域背景
    UIBezierPath *basePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:_startAngle endAngle:endA clockwise:YES];
    //线条宽度
    CGContextSetLineWidth(ctx, _strokeWidth);
    //设置线条顶端
    CGContextSetLineCap(ctx, kCGLineCapRound);
    //线条颜色
    [_pathBackColor setStroke];
    //把路径添加到上下文
    CGContextAddPath(ctx, basePath.CGPath);
    //渲染背景线
    CGContextStrokePath(ctx);
    
    #彩色动态区域
    UIBezierPath *valuePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:_startAngle endAngle:valueEndA clockwise:YES];
    //设置线条顶端
    CGContextSetLineCap(ctx, kCGLineCapRound);
    //线条颜色
    [_pathFillColor setStroke];
    //把路径添加到上下文
    CGContextAddPath(ctx, valuePath.CGPath);
    //渲染数值线
    CGContextStrokePath(ctx);
    
   #画小圆点 使用是 绘制一张图片,其中图片的 Frame 中 x,y 使用到 正弦,余弦函数得到。
    if (_showPoint) {
        CGContextDrawImage(ctx, CGRectMake(CircleSelfWidth/2 + radius*cosf(valueEndA)-_strokeWidth/2.0, CircleSelfWidth/2 + radius*sinf(valueEndA)-_strokeWidth/2.0, _strokeWidth, _strokeWidth), [UIImage imageNamed:@"circle_point"].CGImage);
    }
   # 绘制中间的文字,由于定时器的持续执行刷新,就出现了,文字跳动累加的效果。
   # 其实直接在这里 修改一个全局 label 的值效果是一样的。
    if (_showProgressText) {
        //画文字
        NSString *currentText = [NSString stringWithFormat:@"%.2f%%",fakeProgress*100];
        //段落格式
        NSMutableParagraphStyle *textStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
        textStyle.lineBreakMode = NSLineBreakByWordWrapping;
        textStyle.alignment = NSTextAlignmentCenter;//水平居中
        //字体
        UIFont *font = [UIFont boldSystemFontOfSize:22.0];
        //构建属性集合
        NSDictionary *attributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName:textStyle};
        //获得size
        CGSize stringSize = [currentText sizeWithAttributes:attributes];
        //垂直居中
        CGRect r = CGRectMake((CircleSelfWidth-stringSize.width)/2.0, (CircleSelfHeight - stringSize.height)/2.0,stringSize.width, stringSize.height);
        [currentText drawInRect:r withAttributes:attributes];
    }
    
}

小球图片的坐标计算参照以下这张图

Paste_Image.png

#设置进度 属性的 set 方法
- (void)setProgress:(CGFloat)progress {
    
    _progress = progress;
    fakeProgress = 0.0;
    
    if (timer) {
        [timer invalidate];
        timer = nil;
    }
    
    //如果为0则直接刷新
    if (_progress == 0.0) {
        [self setNeedsDisplay];
        return;
    }
    #生成一个定时器 持续触发  drawRect 方法
    timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(asa ) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    
}
#定时器绑定的方法
- (void)asa
{
    if (fakeProgress >= _progress || fakeProgress >= 1.0f) {
        #最后一次赋准确值 并移除定时器
        fakeProgress = _progress;
        [self setNeedsDisplay];
        
        if (timer) {
            [timer invalidate];
            timer = nil;
        }
        return;
    } else {
        #进度条动画
        [self setNeedsDisplay];
    }
    
    # fakeProgress 数值增加
    if (_animationModel == CircleIncreaseSameTime) {
        fakeProgress += 0.01*(_progress);//不同进度动画时间基本相同
    } else {
        fakeProgress += 0.01;//进度越大动画时间越长。
    }
}
使用 CAShapeLayer 和 CABasicAnimation 实现环形进度动图

</br>

进度.gif

核心源码

# 橘红色的背景
CAShapeLayer *shapeLayer11=[CAShapeLayer layer];
UIBezierPath*path12=[UIBezierPath bezierPathWithOvalInRect:CGRectMake(89, 299, 138, 138)];
# 设置末端的形状为圆形
path12.lineCapStyle = kCGLineCapRound;  
shapeLayer11.path=path12.CGPath;
# 就是图中我们看到的橘红色   CAShapeLayer的fillColor 填充的是 贝塞尔曲线的有效区域   半径为 138的圆
shapeLayer11.fillColor=[UIColor colorWithRed:0.95 green:0.37 blue:0.38 alpha:1.00].CGColor;
# 设置lineWidth 为0
shapeLayer11.lineWidth=0;
 # lineWidth 为0 strokeColor没有效果
//shapeLayer11.strokeColor=[UIColor colorWithRed:0.95 green:0.37 blue:0.38 alpha:1.00].CGColor;
[self.layer addSublayer:shapeLayer11];

# 深绿色的区域
CAShapeLayer *shapeLayer1 = [CAShapeLayer layer];
UIBezierPath *path1 = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(89, 299, 138, 138)];
path1.lineCapStyle = kCGLineJoinRound;
shapeLayer1.path = path1.CGPath;
# 设置内部填充色为 无色
shapeLayer1.fillColor = [UIColor clearColor].CGColor; 
# 设计 lineWidth 为20 (深绿色区域)我们可以看到是绿色区域的中心线在贝塞尔曲线的边界上
shapeLayer1.lineWidth = 20;
shapeLayer1.strokeColor = [UIColor colorWithRed:0.16 green:0.58 blue:0.22 alpha:1.00].CGColor;
[self.layer addSublayer:shapeLayer1];

# strokeEnd为CAShapeLayer的终点,这里设置为动画的 KEY
CABasicAnimation *pathAnima = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnima.duration = 1.5f;
pathAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pathAnima.fromValue = [NSNumber numberWithFloat:0.0f]; 
# 终点值设置为 0.8 
pathAnima.toValue = [NSNumber numberWithFloat:.8f];
pathAnima.fillMode = kCAFillModeForwards;
pathAnima.removedOnCompletion = NO;
[shapeLayer1 addAnimation:pathAnima forKey:nil];
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.01.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • 使用 Core Graphics 和 定时器 实现环形进度动图
      • 使用 CAShapeLayer 和 CABasicAnimation 实现环形进度动图
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档