目标效果
实现
新建基于UIview的文件
.h
属性
/** 0 < accuracy < 1 */ @property (nonatomic,assign) double accuracy;
.m
属性
///画圆Layer @property (nonatomic,strong) CAShapeLayer *shapeLayer; ///底层灰色圆Layer @property (nonatomic,strong) CAShapeLayer *shapeFloorLayer; ///画圆Path @property (nonatomic,strong) UIBezierPath *proPath; @property (nonatomic,strong) UILabel * accuracyLabel; @property (nonatomic,strong) UICountingLabel * aValueLabel; ///圆心 @property (nonatomic,assign) CGPoint roundCenter; ///圆半径 @property (nonatomic, assign) CGFloat radius;
方法
- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setup]; } return self; } - (instancetype)init { self = [super init]; if (self) { [self setup]; } return self; } - (void)setup{ self.backgroundColor = [UIColor whiteColor]; _roundCenter = CGPointMake(self.mqb_width * 0.5, self.mqb_height * 0.5); _radius = (self.mqb_width - 20*mqbScale)/2; [self addSubview:self.aValueLabel]; self.aValueLabel.sd_layout. leftSpaceToView(self, 30*mqbScale). rightSpaceToView(self, 30*mqbScale). centerYIs(_roundCenter.y - 10*mqbScale). heightIs(36*mqbScale); [self addSubview:self.accuracyLabel]; self.accuracyLabel.sd_layout. leftSpaceToView(self, 30*mqbScale). rightSpaceToView(self, 30*mqbScale). topSpaceToView(self.aValueLabel, 15*mqbScale). heightIs(20*mqbScale); self.accuracyLabel.text = @"百分比"; [self.layer addSublayer:self.shapeFloorLayer]; [self.layer addSublayer:self.shapeLayer]; } - (void)setAccuracy:(double)accuracy{ if (accuracy < 0) { _accuracy = 0; }else if (accuracy > 1){ _accuracy = 1; } else { _accuracy = accuracy; } [self startAccuracyAnimation]; [self.aValueLabel countFrom:0 to:(_accuracy*100) withDuration:0.5]; } - (void)startAccuracyAnimation{ [self.proPath addArcWithCenter:_roundCenter radius:_radius startAngle:3 * M_PI/2 endAngle:3 * M_PI/2 + 2 * M_PI * _accuracy clockwise:YES]; self.shapeLayer.path = self.proPath.CGPath; /** 动画1 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; animation.fromValue = @(0.0f); animation.toValue = @(1.0f); animation.duration = 0.5f; [self.shapeLayer addAnimation:animation forKey:@"animationStrokeEnd"]; */ /** 动画2 POPSpringAnimation *popStrokeEnd = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd]; popStrokeEnd.fromValue = @(0.0f); popStrokeEnd.toValue = @(1.0f); popStrokeEnd.springBounciness = 12; popStrokeEnd.springSpeed = 12; [self.shapeLayer pop_addAnimation:popStrokeEnd forKey:@"popAnimationStrokeEnd"]; */ /** 动画3 POPSpringAnimation *popStrokeEnd = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd]; popStrokeEnd.fromValue = @(0.5f); popStrokeEnd.toValue = @(1.0f); popStrokeEnd.springBounciness = 12; popStrokeEnd.springSpeed = 12; [self.shapeLayer pop_addAnimation:popStrokeEnd forKey:@"popAnimationStrokeEnd"]; POPSpringAnimation *popStrokeStart = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeStart]; popStrokeStart.fromValue = @(0.5f); popStrokeStart.toValue = @(0.0f); popStrokeStart.springBounciness = 12; popStrokeStart.springSpeed = 12; [self.shapeLayer pop_addAnimation:popStrokeStart forKey:@"popAnimationStartEnd"]; */ } #pragma mark ========== 变量 ========== - (UILabel *)accuracyLabel{ if (!_accuracyLabel) { _accuracyLabel = [[UILabel alloc]init]; _accuracyLabel.font = mqbFont(15.0); _accuracyLabel.textColor = [UIColor mqb_colorBlack]; _accuracyLabel.textAlignment = NSTextAlignmentCenter; } return _accuracyLabel; } - (UICountingLabel *)aValueLabel{ if (!_aValueLabel) { _aValueLabel = [[UICountingLabel alloc]init]; _aValueLabel.font = mqbMediumFont(40); _aValueLabel.textColor = [UIColor mqb_colorBlack]; _aValueLabel.textAlignment = NSTextAlignmentCenter; _aValueLabel.format = @"%d%%"; } return _aValueLabel; } - (CAShapeLayer *)shapeFloorLayer{ if (!_shapeFloorLayer) { ///细线条 UIColor *colorLine = [UIColor mqb_colorSeparatorColor]; UIBezierPath *pathLine = [UIBezierPath bezierPathWithArcCenter:_roundCenter radius:_radius startAngle:0 endAngle:2 * M_PI clockwise:YES]; _shapeFloorLayer = [CAShapeLayer layer]; _shapeFloorLayer.fillColor = [UIColor clearColor].CGColor; _shapeFloorLayer.strokeColor = colorLine.CGColor; _shapeFloorLayer.lineWidth = 2*mqbScale; _shapeFloorLayer.path = pathLine.CGPath; } return _shapeFloorLayer; } - (CAShapeLayer *)shapeLayer{ if (!_shapeLayer) { _shapeLayer = [CAShapeLayer layer]; _shapeLayer.strokeColor = [UIColor mqb_colorGreen].CGColor; _shapeLayer.fillColor = [UIColor clearColor].CGColor; _shapeLayer.lineWidth = 10*mqbScale;; _shapeLayer.fillRule = kCAFillRuleEvenOdd; _shapeLayer.lineCap = kCALineCapRound; } return _shapeLayer; } - (UIBezierPath *)proPath{ if (!_proPath) { _proPath = [[UIBezierPath alloc]init]; _proPath.lineWidth = 10*mqbScale; _proPath.lineCapStyle = kCGLineCapRound; _proPath.lineJoinStyle = kCGLineJoinRound; } return _proPath; }
备注
代码中用到了SDAutoLayout约束,pop 动画、UICountingLabel 第三方 label 数字动画,UICountingLabel 的 format 原本不支持的百分比格式,如若需要可在源码中 setTextValue 修改:
修改前
- (void)setTextValue:(CGFloat)value { if (self.attributedFormatBlock != nil) { self.attributedText = self.attributedFormatBlock(value); } else if(self.formatBlock != nil) { self.text = self.formatBlock(value); } else { // check if counting with ints - cast to int if([self.format rangeOfString:@"%(.*)d" options:NSRegularExpressionSearch].location != NSNotFound || [self.format rangeOfString:@"%(.*)i"].location != NSNotFound) { self.text = [NSString stringWithFormat:self.format,(int)value]; } else { self.text = [NSString stringWithFormat:self.format,value]; } } }
修改后
- (void)setTextValue:(CGFloat)value { if (self.attributedFormatBlock != nil) { self.attributedText = self.attributedFormatBlock(value); } else if(self.formatBlock != nil) { self.text = self.formatBlock(value); } else { // check if counting with ints - cast to int if([self.format rangeOfString:@"%(.*)d%%" options:NSRegularExpressionSearch].location != NSNotFound || [self.format rangeOfString:@"%(.*)i%%"].location != NSNotFound || [self.format rangeOfString:@"%(.*)d" options:NSRegularExpressionSearch].location != NSNotFound || [self.format rangeOfString:@"%(.*)i"].location != NSNotFound) { self.text = [NSString stringWithFormat:self.format,(int)value]; } else { self.text = [NSString stringWithFormat:self.format,value]; } } }