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

封装环形进度条

作者: 何以_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