美文网首页iOS学习笔记iOS DeveloperIOS
iOS_动画_实例(2)_进度条的实现+渐变进度条的实现

iOS_动画_实例(2)_进度条的实现+渐变进度条的实现

作者: 丶纳凉 | 来源:发表于2017-05-27 09:17 被阅读292次

    一丶原理

    先看下效果:

    无渐变:
    1.png

    由2个圆环,一个背景灰色圆环+一个进度圆环;

    1.圆环

    CAShapeLayer用来显示样式的图层;

    画圆环的方式:

    利用贝塞尔曲线绘制,添加到CAShapeLayer上:

    //弧度=角度*3.14再除以180

    - (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise NS_AVAILABLE_IOS(4_0);
    

    注意

    CAShapeLayer的lineCap属性,设置线的头部形状;

    有无形状+圆形+方形;

    /* The cap style used when stroking the path. Options are butt',round'

    • and square'. Defaults tobutt'. */
    无形状
     NSString *cons kCALineCapButt;
     圆形
     NSString *const kCALineCapRound;
     方形
     NSString *const kCALineCapSquare; 
    

    2.画渐变
    渐变:

    2.png

    CAGradientLayer介绍:

    渐变用到CAGradientLayer这个类;给用的api很少,也很简洁;

    /*

    颜色数组,设置我们需要过的的颜色,必须是CGColor对象

    */

    @property(nullable, copy) NSArray *colors;

    /*

    颜色开始进行过渡的位置

    这个数组中的元素是NSNumber类型,单调递增的,并且在0——1之间

    例如,如果我们设置两个颜色进行过渡,这个数组中写入0.5,则第一个颜色会在达到layer一半的时候开始向第二个颜色过渡

    */

    @property(nullable, copy) NSArray<NSNumber *> *locations;

    /*

    下面两个参数用于设置渲染颜色的起点和终点 取值范围均为0——1

    默认起点为(0.5 ,0) 终点为(0.5 ,1),颜色的过渡范围就是沿y轴从上向下

    */

    @property CGPoint startPoint;

    @property CGPoint endPoint;

    创建两个CAGradientLayer;
    右边采用蓝->黄色渐变;
    左边采用蓝->黄色渐变;
    用Layer把2个层拼接;
    需要显示的部分可以采用mask属性进行设置;
    因为需要圆环,所以直接
    _gradLayer.mask = self.frontShapeLayer;
    就实现渐变圆环;

    要点:
    理论上一个CAGradientLayer就够了;提供2个CAGradientLayer是运输可以设置3种颜色渐变;

    二丶代码

    #import <UIKit/UIKit.h>
    
    @interface ProgressView : UIView
    
    @property (nonatomic, assign) CGFloat progress;
    @property (nonatomic, assign,getter=isGradual) BOOL gradual;
    
    
    /**
     @param gradual 开启渐变,默认关闭;
     */
    - (void)setGradual:(BOOL)gradual;
    /**
     @param progress 进度 [0,1],默认开启
     */
    - (void)setProgress:(CGFloat)progress;
    
    @end
    
    #import "ProgressView.h"
    
    static const CGFloat kLineWidth = 5.0f;
    static const CGFloat kFrontLineWidth = 5.0f;
    #define kColor_Top [UIColor colorWithRed:34/255.0 green:44/255.0 blue:87/255.0 alpha:1]
    #define kColor_Bottom [UIColor colorWithRed:223/255.0 green:157/255.0 blue:16/255.0 alpha:1]
    #define kColor_Background [UIColor colorWithRed:225/255.0 green:224/255.0 blue:233/255.0 alpha:1]
    
    
    @interface ProgressView ()
    
    
    
    @property (strong, nonatomic) CAShapeLayer *frontShapeLayer;
    @property (strong, nonatomic) CAShapeLayer *backShapeLayer;
    @property (strong, nonatomic) UIBezierPath *circleBezierPath;
    //渐变用
    @property (nonatomic, strong) CAGradientLayer *rightGradLayer;
    @property (nonatomic, strong) CAGradientLayer *leftGradLayer;
    @property (nonatomic, strong) CALayer *gradLayer;
    
    @end
    
    @implementation ProgressView
    
    
    -(void)drawRect:(CGRect)rect{
        
        CGFloat kWidth = rect.size.width;
        CGFloat kHeight = rect.size.height;
        
        if (!self.circleBezierPath){
            self.circleBezierPath = ({
                CGPoint pCenter = CGPointMake(kWidth * 0.5, kHeight * 0.5);
                CGFloat radius = MIN(kWidth, kHeight);
                radius = radius - kFrontLineWidth;
                UIBezierPath *circlePath = [UIBezierPath bezierPath];
                [circlePath addArcWithCenter:pCenter radius:radius * 0.5 startAngle:270 * M_PI / 180 endAngle:269 * M_PI / 180 clockwise:YES];
                [circlePath closePath];
                circlePath;
            });
        }
        if (!self.backShapeLayer) {
            self.backShapeLayer = ({
                CAShapeLayer *shapeLayer = [CAShapeLayer layer];
                shapeLayer.frame = rect;
                shapeLayer.path = self.circleBezierPath.CGPath;
                shapeLayer.fillColor = [UIColor clearColor].CGColor;
                shapeLayer.lineWidth = kLineWidth;
                shapeLayer.strokeColor = [UIColor colorWithWhite:0.886 alpha:1.000].CGColor;
                shapeLayer.lineCap = kCALineCapRound;
                [self.layer addSublayer:shapeLayer];
                shapeLayer;
            });
        }
        
        if (!self.frontShapeLayer){
            self.frontShapeLayer = ({
                CAShapeLayer  *shapeLayer = [CAShapeLayer layer];
                shapeLayer.frame = rect;
                shapeLayer.path = self.circleBezierPath.CGPath;
                shapeLayer.fillColor = [UIColor clearColor].CGColor;
                shapeLayer.lineWidth = kFrontLineWidth;
                shapeLayer.strokeColor = [UIColor colorWithRed:0.906 green:0.769 blue:0.125 alpha:1.000].CGColor;
                shapeLayer;
            });
            if (self.gradual) {
                [self addGradLayerWithRect:rect];
                self.frontShapeLayer.lineCap = kCALineCapRound;
                _gradLayer.mask = self.frontShapeLayer;
                [self.layer addSublayer:_gradLayer];
            }else{
                [self.layer addSublayer:self.frontShapeLayer];
            }
        }
        
         [self startAnimationValue:self.progress];
    }
    - (void)addGradLayerWithRect:(CGRect)rect{
        CGFloat kHeight = rect.size.height;
        CGRect viewRect = CGRectMake(0, 0, kHeight, kHeight);
        CGPoint centrePoint = CGPointMake(kHeight/2, kHeight/2);
        
        _leftGradLayer = ({
            CAGradientLayer *leftGradLayer = [CAGradientLayer layer];
            leftGradLayer.bounds = CGRectMake(0, 0, kHeight/2, kHeight);
            leftGradLayer.locations = @[@0.1];
            [leftGradLayer setColors:@[(id)kColor_Top.CGColor,(id)kColor_Bottom.CGColor]];
            leftGradLayer.position = CGPointMake(leftGradLayer.bounds.size.width/2, leftGradLayer.bounds.size.height/2);
            leftGradLayer;
        });
        _rightGradLayer = ({
            CAGradientLayer *rightGradLayer = [CAGradientLayer layer];
            rightGradLayer.locations = @[@0.1];
            rightGradLayer.bounds = CGRectMake(kHeight/2, 0, kHeight/2, kHeight);
            [rightGradLayer setColors:@[(id)kColor_Top.CGColor,(id)kColor_Bottom.CGColor]];
            rightGradLayer.position = CGPointMake(rightGradLayer.bounds.size.width/2+kHeight/2, rightGradLayer.bounds.size.height/2);
            rightGradLayer;
        });
        _gradLayer = ({
            CALayer *gradLayer = [CALayer layer];
            gradLayer.bounds = viewRect;
            gradLayer.position = centrePoint;
            gradLayer.backgroundColor = [UIColor clearColor].CGColor;
            gradLayer;
        });
        [_gradLayer addSublayer:_leftGradLayer];
        [_gradLayer addSublayer:_rightGradLayer];
    }
    - (void)startAnimationValue:(CGFloat)value{
        CABasicAnimation *pathAnima = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        pathAnima.duration = 1.0f;
        pathAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        pathAnima.fromValue = [NSNumber numberWithFloat:0.0f];
        pathAnima.toValue = [NSNumber numberWithFloat:value];
        pathAnima.fillMode = kCAFillModeForwards;
        pathAnima.removedOnCompletion = NO;
        [self.frontShapeLayer addAnimation:pathAnima forKey:@"strokeEndAnimation"];
    }
    
    - (void)setGradual:(BOOL)gradual{
        _gradual = gradual;
        if (gradual) {
            [self.frontShapeLayer removeFromSuperlayer];
            self.frontShapeLayer = nil;
        }else{
            [_gradLayer removeFromSuperlayer];
            _gradLayer = nil;
            [self.frontShapeLayer removeFromSuperlayer];
            self.frontShapeLayer = nil;
        }
    }
    - (void)setProgress:(CGFloat)progress{
        NSAssert(progress >= 0 && progress <=1, @"超出范围");
        _progress = progress;
        [self setNeedsDisplay];
    }
    
    @end
    
    

    三丶代码地址

    https://github.com/k373379320/ZBProgressView

    相关文章

      网友评论

        本文标题:iOS_动画_实例(2)_进度条的实现+渐变进度条的实现

        本文链接:https://www.haomeiwen.com/subject/zxkxfxtx.html