天天看点

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

在很多时候我们都需要使用进度条来帮助我们查看进度,iOS框架自带了

progressView

来供我们使用。可是,如果我们需要圆形的⭕️进度条,那么就需要我们自定义了。嘿嘿,下面来看看怎么搞。😁

基本需求

先创建一个继承自UIView的自定义View。

里面有一个这样的方法:

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
	...
}
           

定义文件里面加入控制进度的东西:

@property (nonatomic, assign) float progress;
- (void)changeProgress:(float)progress;
           

在里面实现:

CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.width / 2);
CGFloat radius = self.bounds.size.width / 2 - 7 / 2;
//半径画出来的圆为路径中心的圆
CGFloat startA = - M_PI_2;  //设置进度条起点位置
CGFloat endA = -M_PI_2 + M_PI * 2 * _progress;  //设置进度条终点位置

//获取环形路径(画一个圆形,填充色透明,设置线框宽度为某值,这样就获得了一个环形)
_progressLayer = [CAShapeLayer layer];
//创建一个track shape layer
_progressLayer.frame = self.bounds;
_progressLayer.fillColor = [[UIColor clearColor] CGColor];
//填充色为无色
_progressLayer.strokeColor = [[UIColor redColor] CGColor];
//指定path的渲染颜色,这里可以设置任意不透明颜色
_progressLayer.opacity = 1; //背景颜色的透明度
_progressLayer.lineWidth = 7;//线的宽度
//_progressLayer.lineCap = kCALineCapButt;
//指定线的边缘类型
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];//上面说明过了用来构建圆形
_progressLayer.path = [path CGPath];
[self.layer addSublayer:_progressLayer];
           

将进度设为不同值,看看效果:

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:
[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

可以发现我们的需求已经大致达成了,我们是使用贝塞尔曲线画出了圆弧,再将进度条

layer

的路径设置为曲线路径就完成了基本需求。

进阶需求

我们还可以同通过使用一系列属性,对这个进度条的各个方面进行一些改进:

_progressLayer.lineCap = kCALineCapRound;
//指定线的边缘是圆的
           

圆角进度条:

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

虚线进度条:

_progressLayer.lineDashPattern = @[@10, @5];
//按照数组中的长度依次打断
           

效果:

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

渐变色进度条:

可以生成一个单一底色:

CALayer *gradientLayer = [CALayer layer];
gradientLayer.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.width);
[gradientLayer setBackgroundColor:[UIColor redColor].CGColor];
           

也可以在上面添加渐变图层:

//左侧渐变色
CAGradientLayer *leftLayer = [CAGradientLayer layer];
leftLayer.frame = CGRectMake(0, 0, self.bounds.size.width / 2, self.bounds.size.width);    // 分段设置渐变色
leftLayer.locations = @[@0.2, @0.8, @1];
leftLayer.colors = @[(id)[UIColor greenColor].CGColor, (id)[UIColor yellowColor].CGColor];
[gradientLayer addSublayer:leftLayer];

//右侧渐变色
CAGradientLayer *rightLayer = [CAGradientLayer layer];
rightLayer.frame = CGRectMake(self.bounds.size.width / 2, 0, self.bounds.size.width / 2, self.bounds.size.height);
rightLayer.locations = @[@0.2, @0.8, @1];
rightLayer.colors = @[(id)[UIColor redColor].CGColor, (id)[UIColor yellowColor].CGColor];
[gradientLayer addSublayer:rightLayer];
           

图层效果:

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

创造出了一个三色渐变图层。为了让进度条颜色变成渐变,我们需要使用:

[gradientLayer setMask:_progressLayer];
//用progressLayer来截取渐变层
           

截取过程是怎么样呢?下面我就使用Keynote为大家演示一下。

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

相当于有两个图形:

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

截获操作相当于使用Keynote多图形操作中的交叉:

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

以小圆图形的形状截取大底色:

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

就获得了带有渐变的圆形轨道。

再将截获的圆轨加到view。

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

就获得了一个渐变圆环。

底轨圆环:

我们上面创建的轨道只有进度条,没有底轨条。为了美观,我们可以加入底轨,也就是相当于创建一个100%进度的底色进度条,再将我们的进度条加到轨道层上面就好啦。

_progressLayer2 = [CAShapeLayer layer];
_progressLayer2.frame = self.bounds;
_progressLayer2.fillColor = [[UIColor clearColor] CGColor];
_progressLayer2.strokeColor = [[UIColor colorWithWhite:0.9 alpha:1] CGColor];
_progressLayer2.opacity = 1;
_progressLayer2.lineWidth = 7;//线的宽度
UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:-M_PI_2 + M_PI * 2 clockwise:YES];
_progressLayer2.path = [path2 CGPath];
[self.layer addSublayer:_progressLayer2];

[_progressLayer2 addSublayer:gradientLayer];
           

实现效果:

[iOS开发]用CAShapeLayer实现圆形进度条基本需求进阶需求小结:

动态进度条:

runloop

中使用计时器控制进度,就可以轻松实现进度条的动画啦

- (void)changeProgress:(float)progress {
    _progress = progress;
    [self setNeedsDisplay];
}
           

小结:

以上就是对进度条的一个使用心得。对layer的使用还在初步入门阶段,还望各位大佬指正。