渐变直线/圆形进度条实现

渐变直线/圆形进度条实现
文章图片
ProgressBar.gif 直线进度条

  • 结构

    渐变直线/圆形进度条实现
    文章图片

    第一部分:背景 view
    第二部分:填充 view,用 CAGradientLayer 填充
  • 核心代码
/* CAGradientLayer 渐变色,目前只有 kCAGradientLayerAxial 一个选项,即呈线性变化 startPoint、endPoint:分别表示渐变层的起始位置和终止位置,这两个点被定义在一个单元坐标空间,[0,0] 表示左上角位置,[1,1] 表示右下角位置,默认值分别是 [0.5,0] and [0.5,1] colors:颜色数组,定义渐变层的各个颜色 locations: 可选的 NSNumber 数组,决定每个渐变颜色的终止位置,这些值必须是递增的,数组的长度和 colors 的长度最好一致 */ - (void)gradientColorForView:(UIView *)view { CAGradientLayer *layer = [CAGradientLayer layer]; layer.startPoint = CGPointMake(0, 0); layer.endPoint = CGPointMake(1, 0); layer.colors = [NSArray arrayWithObjects:(__bridge id)[UIColor colorWithRed:24/255.0 green:201/255.0 blue:255/255.0 alpha:1].CGColor,(__bridge id)[UIColor colorWithRed:0/255.0 green:147/255.0 blue:255/255.0 alpha:1].CGColor, nil]; layer.locations = @[@0,@1]; [view.layer insertSublayer:layer atIndex:0]; }

圆形进度条
  • 首先画个圆,
    这里就需要用到 UIBezierPathCAShapeLayer 了。
@property (nonatomic, strong) UIBezierPath *bezierPath; @property (nonatomic, strong) CAShapeLayer *inCAShapeLayer; self.bezierPath = [UIBezierPath bezierPath]; self.inCAShapeLayer = [CAShapeLayer layer]; self.inCAShapeLayer.lineWidth = self.lineWidth/2; self.inCAShapeLayer.strokeColor = [UIColor colorWithRed:219/255.0 green:219/255.0 blue:219/255.0 alpha:1].CGColor; self.inCAShapeLayer.fillColor = [UIColor whiteColor].CGColor; self.inCAShapeLayer.lineCap = kCALineCapRound [self.layer addSublayer:self.inCAShapeLayer]; [self.bezierPath appendPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2) radius:self.bounds.size.width/2 - self.lineWidth startAngle:0 endAngle:M_PI*2 clockwise:YES]]; self.inCAShapeLayer.path = self.bezierPath.CGPath;

【渐变直线/圆形进度条实现】
渐变直线/圆形进度条实现
文章图片
效果图
CAShapeLayer 是 CALayer 的子类,比 CALayer 更灵活,可以画出各种图形。 fillColor 代表这个 Layer 的填充色, strokeColor 代表这个 Layer 的边框色。
UIBezierPath 贝塞尔曲线,可以用来构建一段弧线,你可以用任意条弧线来组成你想要的形状。
  • 渐变填充色
    渐变色就需要上面用到过的 CAShapeLayer 了。
    先添加左边的:
@property (nonatomic, strong) CALayer *caLayer; @property (nonatomic, strong) CAGradientLayer *leftGradientLayer; self.caLayer = [CALayer layer]; [self.layer addSublayer:self.caLayer]; self.leftGradientLayer = [CAGradientLayer layer]; self.leftGradientLayer.startPoint = CGPointMake(0, 1); self.leftGradientLayer.endPoint = CGPointMake(0, 0); self.leftGradientLayer.colors = [NSArray arrayWithObjects:(__bridge id)[UIColor colorWithRed:237/255.0 green:199/255.0 blue:109/255.0 alpha:1].CGColor,(__bridge id)[UIColor colorWithRed:219.5/255.0 green:181/255.0 blue:100.5/255.0 alpha:1].CGColor, nil]; [self.caLayer addSublayer:self.leftGradientLayer];

渐变直线/圆形进度条实现
文章图片
效果图
在添加右边的:
@property (nonatomic, strong) CAGradientLayer *rightGradientLayer; self.rightGradientLayer = [CAGradientLayer layer]; self.rightGradientLayer.startPoint = CGPointMake(0, 0); self.rightGradientLayer.endPoint = CGPointMake(0, 1); self.rightGradientLayer.colors = [NSArray arrayWithObjects:(__bridge id)[UIColor colorWithRed:219.5/255.0 green:181/255.0 blue:100.5/255.0 alpha:1].CGColor,(__bridge id)[UIColor colorWithRed:202/255.0 green:163/255.0 blue:92/255.0 alpha:1].CGColor, nil]; [self.caLayer addSublayer:self.rightGradientLayer];


渐变直线/圆形进度条实现
文章图片
效果图
然后为 self.caLayer``setMask设置一个遮罩,遮罩范围外面的就不会在显示了。
@property (nonatomic, strong) CAShapeLayer *outCAShapeLayer; self.outCAShapeLayer = [CAShapeLayer layer]; self.outCAShapeLayer.lineWidth = self.lineWidth; self.outCAShapeLayer.fillColor = [UIColor clearColor].CGColor; self.outCAShapeLayer.strokeColor = [UIColor whiteColor].CGColor; self.outCAShapeLayer.lineCap = kCALineCapRound; [self.caLayer setMask:self.outCAShapeLayer]; [self.bezierPath appendPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2) radius:self.bounds.size.width/2 - self.lineWidth startAngle:self.startAngle endAngle:self.endAngle clockwise:YES]]; self.outCAShapeLayer.path = self.bezierPath.CGPath;

渐变直线/圆形进度条实现
文章图片
效果图
  • 添加动画
@property (nonatomic, strong) CABasicAnimation *caAnimation; - (CABasicAnimation *)caAnimation { if (!_caAnimation) { _caAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; _caAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; _caAnimation.fromValue = https://www.it610.com/article/[NSNumber numberWithFloat:0.0f]; _caAnimation.toValue = [NSNumber numberWithFloat:1.0f]; } return _caAnimation; }- (void)setProgress:(CGFloat)progressValue withValueMax:(CGFloat)progressMaxValue { if (progressValue> progressMaxValue) progressValue = https://www.it610.com/article/progressMaxValue; CGFloat allAngle = (progressValue/progressMaxValue) * M_PI * 2; //弧长L=αr 其中 α 为圆心角的弧度数,r 为圆的半径α = L/r self.startAngle = M_PI_2 + (self.lineWidth/2)/(self.bounds.size.width/2 - self.lineWidth); self.endAngle = allAngle + self.startAngle; [self.outCAShapeLayer removeAllAnimations]; if (progressMaxValue) { self.caAnimation.duration = (progressValue/progressMaxValue)*3.0; //添加动画 [self.outCAShapeLayer addAnimation:self.caAnimation forKey:@"strokeEndAnimation"]; } /* -setNeedsLayout 方法:标记为需要重新布局,异步调用 layoutIfNeeded 刷新布局,不立即刷新,但 layoutSubviews 一定会被调用 -layoutIfNeeded 方法:如果,有需要刷新的标记,立即调用 layoutSubviews 进行布局(如果没有标记,不会调用 layoutSubviews) 如果要立即刷新,要先调用 [view setNeedsLayout],把标记设为需要布局,然后马上调用 [view layoutIfNeeded],实现布局。 */ [self setNeedsLayout]; }

完整的Demo下载。

    推荐阅读