封裝環(huán)形進度條

功能:

1. 可改變 背景/中心圖標/文字描述 (此進度圖顯示的刻度為背景圖片)
2. 繪制進度時有動畫和非動畫2種模式,并顯示當(dāng)前value值

效果.gif

1. 創(chuàng)建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)   // 進度圓環(huán)起始角度
#define CATProgressEndAngle       (40)     // 進度圓環(huán)結(jié)束角度

// 3種顏色
#define FYEnvGreenColor UIColorFromRGB(0x00e65c)
#define FYEnvYellowColor UIColorFromRGB(0xffff00)
#define FYEnvRedColor UIColorFromRGB(0xff6462)

@interface JKCircleView () <UIGestureRecognizerDelegate,CAAnimationDelegate>

// 進度圓環(huán)
@property CGFloat     dialRadius;

// 背景圓環(huán)
@property CGFloat     outerRadius;  // 不要設(shè)置除非需要方形頁面
@property CGFloat     arcRadius;    // clipsToBounds時必須<outerRadius
@property CGFloat     arcThickness; // 圓環(huán)寬度
@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];
        
        // 設(shè)置默認值
        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);
        
        // 設(shè)置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];
        
        // 中心數(shù)值
        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];

        // 下方內(nèi)容
        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;   //背景圓環(huán)的背景透明度
        _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. 創(chuàng)建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單位,此處并沒有應(yīng)用
    NSArray *tipArr = @[@"℃",@"m3/h",@"%",@"%",@"%",@"%"];
    //下方描述
    NSArray *meanLabelArr = @[@"溫度(℃)", @"濕度(%RH)", @"有害氣體(PPM)", @"二氧化碳(%)", @"PM2.5(MG/M3)", @"噪音(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. 賦值

    //測試數(shù)據(jù)
    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值為測試出來的誤差值所做的修復(fù),當(dāng)進度超過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;
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,704評論 4 61
  • 無題
    丹紫醬閱讀 242評論 0 0
  • 人生沒有事事如意的時候,卻有事事都不如意的時候
    小柴胡粉絲閱讀 267評論 0 0

友情鏈接更多精彩內(nèi)容