由于项目需要一个环形渐变进度条显示课程,这方便网上的确有很多相关资料但是,都是比较零散的而且,大多数只是放一堆代码就算完了。这里我想详细写一篇我自己实现这个进度条的过程。

实现一个圆弧进度条主要分为三步
一、画圆弧这里用的贝赛尔曲线,就是这个东西:UIBezierPath
二、根据贝塞尔曲线路径画两个圆弧一个底色一个上面的填充色,用到的是这个类CAShapeLayer.h
三、画两个渐变色块,把上面的进度条路径映射到渐变色块上,渐变色块用的是这个东西CAGradientLayer.h

目标效果如图

AirPlay_Movie_2017-11-29_04-42-48.gif

第一步:

  • 我们把图案分解开来,就是一个圆环上面叠加一个圆环,底色的圆环是灰色,而上面的圆环是自定义颜色的。

    • 首先我们画一个圆环,其实就是一个粗的圆形,这里用UIBezierPath来画。
      效果图片:

      代码:

    //贝塞尔曲线画圆弧
    UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.width / 2, self.height / 2) radius:(self.width - 20)/2 startAngle:0 endAngle:2 * M_PI clockwise:YES]; //设置颜色
    [[UIColor blackColor] set]; //线粗细
    circlePath.lineWidth = 10; //开始绘图
    [circlePath stroke];

这里主要要注意这个方法:

+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;

五个参数分别为
center:圆心
radius:半径
startAngle:起始角度
endAngle:终止角度
clockwise:是否顺时针画图
主要难理解的是startAngle 和 endAngle

在OC的官方文档中这样规定:

官方文档画圆弧.jpg

所以我要画出目标圆弧就需要从 3π/4 开始到 1π/4结束
方法改为:

UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.width / 2, self.height / 2) radius:(self.width - 20)/2 startAngle:M_PI / 4 + M_PI / 2 endAngle:M_PI / 4 clockwise:YES];

效果图:

黑色圆弧路径.jpg

第二步:

  • 根据第一步画好的路径通过CAShapeLayer 画到layer层上去
    先画灰色一圈:
    CAShapeLayer *bgLayer = [CAShapeLayer layer];
bgLayer.frame = self.bounds;
bgLayer.fillColor = [UIColor clearColor].CGColor;//填充色 - 透明
bgLayer.lineWidth = 20.f;
bgLayer.strokeColor = ZCCRGBColor(212, 212, 212, 1.0).CGColor;//线条颜色
bgLayer.strokeStart = 0;//起始点
bgLayer.strokeEnd = 1;//终点
bgLayer.lineCap = kCALineCapRound;//让线两端是圆滑的状态
bgLayer.path = circlePath.CGPath;//这里就是把背景的路径设为之前贝塞尔曲线的那个路径
[self.layer addSublayer:bgLayer];

效果图:

弧形进度条底色.jpg
  • 画出进度条圆弧
_shapeLayer = [CAShapeLayer layer];
_shapeLayer.frame = self.bounds;
_shapeLayer.fillColor = [UIColor clearColor].CGColor;
_shapeLayer.lineWidth = 20.f;
_shapeLayer.lineCap = kCALineCapRound;
// _shapeLayer.strokeColor = color.CGColor;
_shapeLayer.strokeColor = [UIColor blueColor].CGColor;
_shapeLayer.strokeStart = 0;
_shapeLayer.strokeEnd = 0.8;
_shapeLayer.path = circlePath.CGPath;
[self.layer addSublayer:_shapeLayer];

代码和上面大致一样就是改一下颜色还有 strokenEnd属性 让进度不是全满的,效果图如下:

蓝色进度条.jpg

第三步:
以上完成了基础的两步。现在就是最麻烦的渐变色这一块了。首先熟悉下处理渐变色的那个layer类,CAGradientLayer这个也是layer的子类,我这直接那例子讲吧

//初始化一个渐变图层
CAGradientLayer *leftGradientLayer = [CAGradientLayer layer];
//设frame
leftGradientLayer.frame = CGRectMake(0, 0, self.width / 2, self.height);
//设渐变颜色
//ZCCRGBColor是我自定义的宏 #define ZCCRGBColor(a,b,c,al) [UIColor colorWithRed:a/255.0 green:b/255.0 blue:c/255.0 alpha:al]
[leftGradientLayer setColors:[NSArray arrayWithObjects:(id)ZCCRGBColor(255, 255, 0, 1).CGColor, (id)ZCCRGBColor(255, 0, 0, 1).CGColor, nil]];
//这里设置渐变色渐变范围 0到1就是整个leftGradientLayer上都在渐变
[leftGradientLayer setLocations:@[@0,@1]];
//下面这两个就是渐变色方向Y越大就是越下面 所以是从下到上从黄到红渐变
[leftGradientLayer setStartPoint:CGPointMake(0, 1)];
[leftGradientLayer setEndPoint:CGPointMake(0, 0)];
添加到父图层
[_gradientLayer addSublayer:leftGradientLayer];

看一下效果图

左边从下到上渐变图层.jpg

修改下这个方法

 [leftGradientLayer setLocations:@[@0,@0.5]];

效果图:

只有一半是渐变的.jpg

只有一边渐变上半部分全红。

再修改下这个属性 主要控制渐变色方向

     [leftGradientLayer setLocations:@[@0,@1]];
[leftGradientLayer setStartPoint:CGPointMake(0, 1)];
[leftGradientLayer setEndPoint:CGPointMake(1, 0)];

这样就是对角线的渐变 效果图如下:

对角线渐变.jpg

所以简单点就是这样做渐变色的环 先设置宽高和环一样如下图

渐变色整块.jpg

然后再加下面这条代码 就能把渐变色图层颜色映射到环的layer上面

[self.gradientLayer setMask:_shapeLayer];

效果图

对角线渐变色圆弧.jpg

但是这里其实有个问题,当圆弧进度满的时候就能看到如下图:

对角线渐变圆弧全.jpg

可以看到上面图片的右下角并没有那么红所以不是真正的渐变。那么到底如何做到真正的渐变圆环呢?

其实上面刚开始画渐变图层的时候我就埋了个伏笔。

而且煞费苦心的测试了渐变图层的那几个属性,其实就是为了如下的效果:

左右渐变图层.jpg

然后映射到圆弧上如下效果图:

左右渐变块映射的圆弧.jpg

到这里其实还有个问题就是顶部过度会有一个明显的断层
所以我们就要用到[leftGradientLayer setLocations:@[@0,@0.5]];这个属性了 设置渐变色范围。让顶部渐变色基本不动

左边的渐变色块:
[leftGradientLayer setLocations:@[@0,@0.9]];
右边的渐变色块:
[rightGradientLayer setLocations:@[@0.1, @1]];

再看看效果图

图片.png

好了 这就差不多完成一个渐变色圆弧了,如果强迫症的朋友其实可以弄四个渐变色块从 左下→左上→右上→右下 依次渐变再映射,那样就会更加完美。

终于写完了。。新手第一次写这样的教学文 有什么错误的地方还请多包涵指出,不懂得可以留言问我

最后,动画是怎么实现的呢??
是通过timer 设置_shapeLayer.strokeEnd这个 strokEnd属性实现的
以下是具体代码~

- (void)animateToProgress:(CGFloat)progress{

//    NSLog(@"增加到progress%lf", progress);

    if(_shapeLayer.strokeEnd != 0){
[self animateToZero];
} __weak typeof(self)weakSelf = self; NSLog(@"-----%lf",_shapeLayer.strokeEnd); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_shapeLayer.strokeEnd * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [weakSelf deleteTimer]; NSString *progressStr = [NSString stringWithFormat:@"%lf",progress]; NSDictionary *userInfo = @{@"progressStr":progressStr}; weakSelf.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:weakSelf selector:@selector(animate:) userInfo:userInfo repeats:YES];
}); } - (void)animate:(NSTimer *)time{ CGFloat progress = [[time.userInfo objectForKey:@"progressStr"] floatValue]; if(_shapeLayer.strokeEnd <= progress)
{
_shapeLayer.strokeEnd += 0.01;
}else{
[self deleteTimer];
}
}
//回滚到0 先判断 timer 有没有存在 存在 就把timer 删除
- (void)animateToZero{ // NSLog(@"删除到0"); [self deleteTimer]; self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(animateReset) userInfo:nil repeats:YES];
} - (void)animateReset{ if(_shapeLayer.strokeEnd > 0){
_shapeLayer.strokeEnd -= 0.01;
}else{
[self deleteTimer];
} } - (void)deleteTimer{
[self.timer invalidate];
self.timer = nil;
}

完整代码gitHub链接

作者:zcc_ios
链接:https://www.jianshu.com/p/edbc647ff178
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

iOS圆弧渐变进度条的实现的更多相关文章

  1. 【iOS】环形渐变进度条实现

    之前有人在找渐变进度条的效果,闲来无事就顺手写了一个,然后画了视图层级,方便讲解. 环境信息: Mac OS X 10.10.3 Xcode 6.3.1 iOS 8.3 效果图: 源码下载地址: ht ...

  2. 自定义控件之圆形颜色渐变进度条--SweepGradient

    前几天在群里面有人找圆形可颜色渐变进度条,其中主要的知识点是SweepGradient: mSweepGradient = new SweepGradient(240, 360, new int[] ...

  3. Xamarin iOS教程之进度条和滚动视图

    Xamarin iOS教程之进度条和滚动视图 Xamarin iOS 进度条 进度条可以看到每一项任务现在的状态.例如在下载的应用程序中有进度条,用户可以很方便的看到当前程序下载了多少,还剩下多少.Q ...

  4. iOS 渐变进度条

    #import <UIKit/UIKit.h> @interface JianBianView : UIView //为了增加一个表示进度条的进行,可们可以使用mask属性来屏蔽一部分 @ ...

  5. canvas锥形渐变进度条

    从一个渐变圆角进度条浅出画一个圆 开始 这一切需要从一个(简单)的需求开始,在最开始对设计第一眼看到这张图的时候,感觉挺简单的嘛,直接用echarts饼图模拟出来一个就好了 echarts 然后上ec ...

  6. android自己定义渐变进度条

    项目中须要用到一个弧形渐变的进度条,通过android自带是不能实现的.我是没有找到实现的方法,有大神知道的能够指点.效果图是以下这种 这是通过继承VIew来绘制出来的,网上也有相似的,可是代码那是相 ...

  7. vue 渐变 进度条 progress

    废话 不多少说 ,直接上代码 新建文件 gradual-progress.vue <!-- * @Author: gfc * @Date: 2019-11-07 14:00:11 * @Last ...

  8. svg和css3创建环形渐变进度条

    在负责的项目中,有一个环形渐变读取进度的效果的需求,于是在网上查阅相关资料整理一下.代码如下: <!DOCTYPE html> <html lang="en"&g ...

  9. iOS学习-圆形进度条

    效果: #import <UIKit/UIKit.h> @interface HsProfitRatePieWidgets : UIView { UILabel *_textLabel; ...

随机推荐

  1. osg MatrixManipulator CameraManipulator

    <osgGA/MatrixManipulator>:No such file or directory 修改为 #include <osgGA/CameraManipulator&g ...

  2. IDEA同一项目启动多个实例

    为了验证负载均衡,服务提供者(EurekaClientServiceProviderApplication)需要启动多个实例,当前已启动了一个实例,端口号8762: -- :: --- [ main] ...

  3. spring redistemplate中setHashValueSerializer的设置

    笔者曾经对redis键值使用了不同类型的序列化方法 用过默认值.JdkSerializationRedisSerializer.StringRedisSerializer还用改以下自定类型的序列化工具 ...

  4. IDEA的查询引用、调用关系图的功能(转)

    转自: http://www.cnblogs.com/ghj1976/p/5382455.html Eclipse的"Call Hierarchy"可以查看一个Java方法或类成员 ...

  5. css调用字体 没装微软雅黑,用css写@font-face让其能显示微软雅黑字体

    在设计布局网页时 经常想要用一些比较好看的字体,比如微软雅黑,这个字体在近年来在网页设计中运用越来越平常, 然而所使用的字体也只有自己能看到 到别的机子上 又恢复了原来的宋体神马的. 经过一位高手的提 ...

  6. 【FFMPEG】I,P,B帧和PTS,DTS时间戳的关系

    FFmpeg里有两种时间戳:DTS(Decoding Time Stamp)和PTS(Presentation Time Stamp). 顾名思义,前者是解码的时间,后者是显示的时间.要仔细理解这两个 ...

  7. 【计算机视觉】纹理特征之LBP局部二值化模式

    转自http://blog.csdn.NET/ty101/article/details/8905394 本文的PDF版本,以及涉及到的所有文献和代码可以到下列地址下载: 1.PDF版本以及文献:ht ...

  8. Linux集群环境准备及20项基础优化

    中小规模集群架构: 1.什么是集群? 简单地说,集群就是一堆机器 做同一件事, 例如:京东(www.jd.com)提供卖东西服务这就是一件事,可能是几千台服务器,在背后运转支撑这个网站. www.ba ...

  9. Target Sum

    You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symb ...

  10. C语言细节

    一些常见细节 int *p[]和 int (*p)[] 的区别 int *p[4]; //定义一个指针数组,该数组中每个元素是一个指针,每个指针指向哪里就需要程序中后续再定义了. int (*p)[4 ...