美文网首页
封装环形进度条

封装环形进度条

作者: 何以_aaa | 来源:发表于2016-12-27 14:17 被阅读28次

    功能:

    1. 可改变 背景/中心图标/文字描述 (此进度图显示的刻度为背景图片)
    2. 绘制进度时有动画和非动画2种模式,并显示当前value值

    效果.gif

    1. 创建FYCircleView继承UIView

    FYCircleView.h:

    @interface FYCircleView : UIView
    
    @property int minNum;
    @property int maxNum;
    
    @property NSString *units;
    
    @property(nonatomic,strong) NSString *backImageName;
    @property(nonatomic,strong) NSString *iconName;
    @property(nonatomic,strong) NSString *meaningStr;
    //进度 [0...1]
    @property(nonatomic,assign) CGFloat lastProgress;
    @property(nonatomic,assign) CGFloat progress;
    
    @property int flag;
    
    @property (nonatomic,copy) void (^progressChange)(NSString *result,int flag);
    
    - (void)updateProgress:(CGFloat)progress animation:(BOOL)animationed color:(UIColor *)color value:(int)value;
    
    @end
    

    FYCircleView.m:

    #define DEGREES_TO_RADIANS(degrees)  ((M_PI * degrees)/ 180)
    #define CATProgressStartAngle     (-220)   // 进度圆环起始角度
    #define CATProgressEndAngle       (40)     // 进度圆环结束角度
    
    // 3种颜色
    #define FYEnvGreenColor UIColorFromRGB(0x00e65c)
    #define FYEnvYellowColor UIColorFromRGB(0xffff00)
    #define FYEnvRedColor UIColorFromRGB(0xff6462)
    
    @interface JKCircleView () <UIGestureRecognizerDelegate,CAAnimationDelegate>
    
    // 进度圆环
    @property CGFloat     dialRadius;
    
    // 背景圆环
    @property CGFloat     outerRadius;  // 不要设置除非需要方形页面
    @property CGFloat     arcRadius;    // clipsToBounds时必须<outerRadius
    @property CGFloat     arcThickness; // 圆环宽度
    @property CGPoint     trueCenter;
    @property UILabel     *numberLabel;
    @property UILabel     *meaningLabel;
    @property UIImageView *iconImage;
    @property UIImageView *backImage;
    
    @property int         currentNum;
    @property double      angle;
    
    @property (nonatomic, strong) CAShapeLayer *trackLayer;
    @property (nonatomic, strong) CAShapeLayer *progressLayer;
    
    @property (nonatomic, strong) NSTimer *timer;
    
    @end
    
    @implementation JKCircleView
    
    - (id) initWithFrame:(CGRect)frame{
        self = [super initWithFrame:frame];
        if(self){
            
            self.userInteractionEnabled = YES;
            self.clipsToBounds = YES;
            self.backgroundColor = [UIColor clearColor];
            
            // 设置默认值
            self.minNum = 0;
            self.maxNum = 100;
            self.currentNum = self.minNum;
            self.units = @"";
            self.iconName = @"温度";
            self.backImageName = @"背景";
            self.lastProgress = 0.0;
            
            CGFloat width = frame.size.width;
            CGFloat height = frame.size.height;
            self.trueCenter = CGPointMake(width/2, height/2);
            
            // 设置radius
            self.dialRadius = 10;
            self.arcRadius = 80;
            self.outerRadius = MIN(width, height)/2;
            self.arcThickness = 8.0;
            
            // 背景图片
            self.backImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, width, height-30)];
            self.backImage.image = [UIImage imageNamed:self.backImageName];
            [self addSubview:self.backImage];
            
            // 中心数值
            self.numberLabel = [[UILabel alloc] initWithFrame:CGRectMake(width*.1, height/2 - width/6, 85, 25)];
            self.numberLabel.text = [NSString stringWithFormat:@"%d", self.currentNum];
            self.numberLabel.center = CGPointMake(self.trueCenter.x, self.trueCenter.y+20);
            self.numberLabel.textAlignment = NSTextAlignmentCenter;
            self.numberLabel.font = [UIFont systemFontOfSize:16];
            self.numberLabel.textColor = [UIColor whiteColor];
            [self addSubview:self.numberLabel];
            
            // 中心图标
            self.iconImage = [[UIImageView alloc] initWithFrame:CGRectMake(width*.1, height/2 - width/6, 35, 35)];
            self.iconImage.center = CGPointMake(self.trueCenter.x, self.trueCenter.y - 10);
            self.iconImage.image = [UIImage imageNamed:self.iconName];
            [self addSubview:self.iconImage];
    
            // 下方内容
            self.meaningLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, height - 20, width, 20)];
            self.meaningLabel.text = [NSString stringWithFormat:@"%@",self.meaningStr];
            self.meaningLabel.textAlignment = NSTextAlignmentCenter;
            self.meaningLabel.font = [UIFont systemFontOfSize:14];
            self.meaningLabel.textColor = [UIColor whiteColor];
            [self addSubview:self.meaningLabel];
            
            // 背景轨道
            _trackLayer=[CAShapeLayer layer];
            _trackLayer.frame = self.bounds;
            _trackLayer.fillColor = [UIColor clearColor].CGColor;
            _trackLayer.strokeColor = [UIColor whiteColor].CGColor;
            _trackLayer.opacity = 0.25;   //背景圆环的背景透明度
            _trackLayer.lineCap = kCALineCapRound;
            [self.layer addSublayer:_trackLayer];
            
            self.arcRadius = MIN(self.arcRadius, self.outerRadius - self.dialRadius);
            UIBezierPath *path=[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2) radius:self.arcRadius startAngle:DEGREES_TO_RADIANS(CATProgressStartAngle) endAngle:DEGREES_TO_RADIANS(CATProgressEndAngle) clockwise:YES];//-210到30的path
            _trackLayer.path = path.CGPath;
            _trackLayer.lineWidth = self.arcThickness;
            
            // 进度轨道
            _progressLayer = [CAShapeLayer layer];
            _progressLayer.frame = self.bounds;
            _progressLayer.fillColor = [[UIColor clearColor] CGColor];
            _progressLayer.strokeColor = FYEnvGreenColor.CGColor; //!不能用clearColor
            _progressLayer.lineCap=kCALineCapRound;
            _progressLayer.strokeEnd = 0.0;
            [self.layer addSublayer:_progressLayer];
            
            self.arcRadius = MIN(self.arcRadius, self.outerRadius - self.dialRadius);
            CGFloat start = CATProgressStartAngle;
            CGFloat end = CATProgressEndAngle;
            UIBezierPath *path1=[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2) radius:self.arcRadius startAngle:DEGREES_TO_RADIANS(start) endAngle:DEGREES_TO_RADIANS(end) clockwise:YES];//-210到30的path
            
            _progressLayer.path = path1.CGPath;
            _progressLayer.lineWidth = self.arcThickness;
        
        }
        return self;
    }
    
    - (void)setProgress:(CGFloat)progress {
        _progress = progress;
        
        if (progress < 0.0) _progress = 0.0;
        if (progress > 1.0) _progress = 1.0;
    }
    
    - (void)updateProgress:(CGFloat)progress animation:(BOOL)animationed color:(UIColor *)color value:(int)value{
        
        self.progress = progress;
        [self.progressLayer removeAllAnimations];
        
        // 非动画形式
        if (!animationed) {
            
            [CATransaction begin];
            [CATransaction setDisableActions:YES];
            [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
            [CATransaction setAnimationDuration:0.5];
            
            self.progressLayer.strokeEnd = self.progress;
    
            self.currentNum = self.minNum + (self.maxNum - self.minNum)*progress;
            self.numberLabel.text = [NSString stringWithFormat:@"%d", self.currentNum];
            if (self.progressChange) {
                self.progressChange([NSString stringWithFormat:@"%d",self.currentNum],self.flag);
            }
            [CATransaction commit];
            
        //动画形式
        } else {
            
            CABasicAnimation *animation= [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
            animation.fromValue = @(self.lastProgress);
            animation.toValue = @(progress);
            animation.duration = 1.5 * self.progress;
            animation.removedOnCompletion = YES;
            animation.delegate = self;
            animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
            
            _progressLayer.strokeColor = color.CGColor;
            
            self.progressLayer.strokeEnd = self.progress;
            
            [self.progressLayer addAnimation:animation forKey:@"strokeEndAnimation"];
    
            self.currentNum = value;
            self.numberLabel.text = [NSString stringWithFormat:@"%d", self.currentNum];
            if (self.progressChange) {
                self.progressChange([NSString stringWithFormat:@"%d",self.currentNum],self.flag);
            }
     
        }
        self.lastProgress = progress;
    }
    
    - (void) willMoveToSuperview:(UIView *)newSuperview{
        [super willMoveToSuperview:newSuperview];
        
        self.arcRadius = MIN(self.arcRadius, self.outerRadius - self.dialRadius);
    
        self.numberLabel.text = [NSString stringWithFormat:@"%d", self.currentNum];
        self.meaningLabel.text = [NSString stringWithFormat:@"%@",self.meaningStr];
        self.backImage.image = [UIImage imageNamed:self.backImageName];
        self.iconImage.image = [UIImage imageNamed:self.iconName];
    }
    

    2. 创建view

        //背景图片
        NSArray *backImageArr = @[@"temperature_back",
                                  @"wet_back",
                                  @"posionGas_back",
                                  @"carbonDioxide_back",
                                  @"PM2.5_back",
                                  @"noise_back"];
        //图标
        NSArray *imageArr = @[@"temperature_icon",
                              @"wet_icon",
                              @"posionGas_icon",
                              @"carbonDioxide_icon",
                              @"PM2.5_icon",
                              @"noise_icon"];
        //value单位,此处并没有应用
        NSArray *tipArr = @[@"℃",@"m³/h",@"%",@"%",@"%",@"%"];
        //下方描述
        NSArray *meanLabelArr = @[@"温度(℃)", @"湿度(%RH)", @"有害气体(PPM)", @"二氧化碳(%)", @"PM2.5(MG/M³)", @"噪音(DB)"];
        
        CGFloat W = FYProgressLoop_W;
        CGFloat H = FYProgressLoop_H;
        CGFloat marginX = (SCREEN_WIDTH - W*2 - FYViewMagin*2)/2;
        
        for (int i = 0; i < 6; i++) {
            
            int col_idx = i % 2;  //列索引
            int row_idx = i / 2;  //行索引
            CGFloat X = FYViewMagin + col_idx * (W + 2*marginX);
            CGFloat Y = 60 + row_idx * (H + 20);
            JKCircleView *dialView = [[JKCircleView alloc] initWithFrame:CGRectMake(X, Y, W, H)];
            
            //取值范围:最大值、最小值
            dialView.minNum = 0;
            if (i == 0) dialView.maxNum = 35;
            if (i == 1) dialView.maxNum = 100;
            if (i == 2) dialView.maxNum = 180;
            if (i == 3) dialView.maxNum = 1500;
            if (i == 4) dialView.maxNum = 100;
            if (i == 5) dialView.maxNum = 150;
            
            dialView.flag = i+100;
            dialView.tag = i+100;
            dialView.units = tipArr[i];                  //单位名称
            dialView.backImageName = backImageArr[i];    //背景图片
            dialView.iconName = imageArr[i];             //中间图标
            dialView.progress = 0.0;
            dialView.meaningStr = meanLabelArr[i];
            
            [self.view addSubview:dialView];
        }
    

    3. 赋值

        //测试数据
        wendu1 = [self getRandomNumberFrom:15 to:35];
        wet2 = 36;
        posionGas3 = [self getRandomNumberFrom:20 to:130];
        eyht4 = [self getRandomNumberFrom:200 to:1200];
        PM5 = [self getRandomNumberFrom:0 to:80];
        noise6 = [self getRandomNumberFrom:0 to:90];
    
        // 注意:此f值为测试出来的误差值所做的修复,当进度超过50%不会有误差,小于50%时会有。
        CGFloat f = 0.03;
        for (int i = 0; i < 6; i++) {
            JKCircleView *dialView = [self.view viewWithTag:100+i];
            switch (i) {
                case 0:
                    [dialView updateProgress:(wendu1*1.0/35>0.5||wendu1*1.0/35<f ? wendu1*1.0/35 : wendu1*1.0/35-f)animation:YES color:_wenduColor value:wendu1];
                    break;
                case 1:
                    [dialView updateProgress:(wet2*1.0/100>0.5||wet2*1.0/100<f ? wet2*1.0/100 : wet2*1.0/100-f) animation:YES color:_wetColor value:wet2];
                    break;
                case 2:
                    [dialView updateProgress:(posionGas3*1.0/180>0.5||posionGas3*1.0/180<f ? posionGas3*1.0/180 : posionGas3*1.0/180-f) animation:YES color:_posionGasColor value:posionGas3];
                    break;
                 case 3:
                    [dialView updateProgress:(eyht4*1.0/1500>0.5||eyht4*1.0/1500<f ? eyht4*1.0/1500 : eyht4*1.0/1500-f) animation:YES color:_eyhtColor value:eyht4];
                    break;
                case 4:
                    [dialView updateProgress:(PM5*1.0/100>0.5||PM5*1.0/100>0.5<f ? PM5*1.0/100 : PM5*1.0/100-f) animation:YES color:_PMColor value:PM5];
                    break;
                case 5:
                    [dialView updateProgress:(noise6*1.0/150>0.5||noise6*1.0/150<f ? noise6*1.0/150 : noise6*1.0/150-f) animation:YES color:_noiseColor value:noise6];
                    break;
                default:
                    break;
            }
        }
    

    相关文章

      网友评论

          本文标题:封装环形进度条

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