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

2017-12-05  本文已影响0人  Junetaurus
ProgressBar.gif

直线进度条

/*
 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];
}

圆形进度条

@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 贝塞尔曲线,可以用来构建一段弧线,你可以用任意条弧线来组成你想要的形状。
@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 = [NSNumber numberWithFloat:0.0f];
        _caAnimation.toValue = [NSNumber numberWithFloat:1.0f];
    }
    return _caAnimation;
}

- (void)setProgress:(CGFloat)progressValue withValueMax:(CGFloat)progressMaxValue {
    if (progressValue > progressMaxValue) progressValue = 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下载

上一篇下一篇

猜你喜欢

热点阅读