// // HKPieChartView.m // PieChart // // Created by hukaiyin on 16/6/20. // Copyright © 2016年 HKY. All rights reserved. // #import "HKPieChartView.h" #define cycle_blue RGB(174, 191, 228) #define cycle_green RGB(66, 116, 130) @interface HKPieChartView() @property (nonatomic, strong) CAShapeLayer *trackLayer; @property (nonatomic, strong) CAShapeLayer *progressLayer; @property (nonatomic, strong) CAGradientLayer *gradientLayer; @property (nonatomic, assign) UIColor *trackColor; @property (nonatomic, assign) UIColor *progressColor; @property (nonatomic, assign) CGFloat lineWidth; @property (nonatomic, strong) UIBezierPath *path; @property (nonatomic, assign) CGFloat percent; //饼状图显示的百分比,最大为100 @property (nonatomic, assign) CGFloat animationDuration;//动画持续时长 @property (nonatomic, strong) NSTimer *timer; @property (nonatomic, strong) UIImageView *shadowImageView; @property (nonatomic, assign) CGFloat pathWidth; @property (nonatomic, assign) CGFloat sumSteps; @property (nonatomic, strong) UILabel *progressLabel; @property (nonatomic, assign) BOOL panAnimationing; @end @implementation HKPieChartView #pragma mark - Life Cycle - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self updateUI]; } return self; } -(void)awakeFromNib { [super awakeFromNib]; [self updateUI]; } - (void)updateUI { // self.trackColor = RGB(240, 244, 251); self.trackColor = [UIColor clearColor]; self.progressColor = cycle_green; self.animationDuration = 100; self.pathWidth = self.frame.size.width - kSizeFrom750(8); [self shadowImageView]; [self trackLayer]; [self gradientLayer]; [self loadGesture]; } - (void)dealloc { [self invalidateTimer]; } - (void)removeFromSuperview { [super removeFromSuperview]; [self invalidateTimer]; } #pragma mark - Load - (void)loadLayer:(CAShapeLayer *)layer WithColor:(UIColor *)color { CGFloat layerWidth = self.pathWidth; CGFloat layerX = (self.bounds.size.width - layerWidth)/2; layer.frame = CGRectMake(layerX, layerX, layerWidth, layerWidth); layer.fillColor = [UIColor clearColor].CGColor; layer.strokeColor = color.CGColor; layer.lineCap = kCALineCapButt; layer.lineWidth = self.lineWidth; layer.path = self.path.CGPath; } - (void)loadGesture { UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(didPan:)]; [self addGestureRecognizer:pan]; } #pragma mark - Gesture Action - (void)didPan:(UIPanGestureRecognizer *)pan { if (!self.panAnimationing) { } } -(void)setInCounting:(BOOL)inCounting{ _inCounting = inCounting; } #pragma mark - Animation - (void)updatePercent:(CGFloat)percent animation:(BOOL)animationed { self.percent = percent; [self.progressLayer removeAllAnimations]; if (!animationed) { [CATransaction begin]; [CATransaction setDisableActions:YES]; [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]]; [CATransaction setAnimationDuration:1]; self.progressLayer.strokeEnd = self.percent / 100.0; [CATransaction commit]; } else { CABasicAnimation *animation= [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; animation.fromValue = @(0.0); animation.toValue = @(self.percent / 100.); animation.duration = self.animationDuration * self.percent / 100; animation.removedOnCompletion = YES; animation.delegate = self; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; self.progressLayer.strokeEnd = self.percent / 100; [self.progressLayer addAnimation:animation forKey:@"strokeEndAnimation"]; } } #pragma mark - CAAnimationDelegate - (void)animationDidStart:(CAAnimation *)anim { self.timer = [NSTimer timerWithTimeInterval:1/60 target:self selector:@selector(timerAction) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes]; } - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { if (flag) { [self invalidateTimer]; if (self.inCounting&&self.percent==0) { self.progressLabel.text = @"未开始"; }else { self.progressLabel.text = [NSString stringWithFormat:@"%.0f%%", self.percent]; } } } - (void)timerAction { id strokeEnd = [[_progressLayer presentationLayer] valueForKey:@"strokeEnd"]; if (![strokeEnd isKindOfClass:[NSNumber class]]) { return; } CGFloat progress = [strokeEnd floatValue]; if (self.inCounting&&progress==0) { self.progressLabel.text = @"未开始"; }else { self.progressLabel.text = [NSString stringWithFormat:@"%0.f%%",floorf(progress * 100)]; } } - (void)invalidateTimer { if (!self.timer) { return; } [self.timer invalidate]; self.timer = nil; } #pragma mark - Getters & Setters - (CAShapeLayer *)trackLayer { if (!_trackLayer) { _trackLayer = [CAShapeLayer layer]; [self loadLayer:_trackLayer WithColor:self.trackColor]; [self.layer addSublayer:_trackLayer]; } return _trackLayer; } - (UIImageView *)shadowImageView { if (!_shadowImageView) { _shadowImageView = [[UIImageView alloc]initWithFrame:self.bounds]; CGPoint center = CGPointMake(CGRectGetWidth(self.bounds)/2, CGRectGetHeight(self.bounds)/2); CGFloat radius = (self.frame.size.width- kSizeFrom750(8)*2)/2; CGFloat startA = -M_PI_2; //设置进度条起点位置 CGFloat endA =-M_PI_2+ M_PI * 2; //设置进度条终点位置 //获取环形路径(画一个圆形,填充色透明,设置线框宽度为10,这样就获得了一个环形) CAShapeLayer * _backLayer = [CAShapeLayer layer];//创建一个track shape layer _backLayer.frame = self.bounds; _backLayer.fillColor = [[UIColor clearColor] CGColor]; //填充色为无色 _backLayer.strokeColor = [cycle_blue CGColor]; //指定path的渲染颜色,这里可以设置任意不透明颜色-淡蓝色 _backLayer.opacity = 1; //背景颜色的透明度 _backLayer.lineCap = kCALineCapRound;//指定线的边缘是圆的 _backLayer.lineWidth = kSizeFrom750(8);//线的宽度 UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];//上面说明过了用来构建圆 _backLayer.path =[path CGPath]; //把path传递給layer,然后layer会处理相应的渲染,整个逻辑和CoreGraph是一致的。 [_shadowImageView.layer addSublayer:_backLayer]; [self addSubview:_shadowImageView]; } return _shadowImageView; } - (CAShapeLayer *)progressLayer { if (!_progressLayer) { _progressLayer = [CAShapeLayer layer]; [self loadLayer:_progressLayer WithColor:self.progressColor]; _progressLayer.lineCap = kCALineCapRound; _progressLayer.strokeEnd = 0; } return _progressLayer; } - (CAGradientLayer *)gradientLayer { if (!_gradientLayer) { _gradientLayer = [CAGradientLayer layer]; _gradientLayer.frame = self.bounds; _gradientLayer.borderColor = cycle_green.CGColor; // _gradientLayer.colors = @[(id)[UIColor cyanColor].CGColor, // (id)[UIColor colorWithRed:0.000 green:0.502 blue:1.000 alpha:1.000].CGColor]; // _gradientLayer.colors = @[(id)HEXCOLOR(@"#4294f8").CGColor,(id)HEXCOLOR(@"#3b82f6").CGColor]; // [_gradientLayer setStartPoint:CGPointMake(0.5, 1.0)]; // [_gradientLayer setEndPoint:CGPointMake(0.5, 0.0)]; [_gradientLayer setMask:self.progressLayer]; [self.layer addSublayer:_gradientLayer]; } return _gradientLayer; } - (UILabel *)progressLabel { if (!_progressLabel) { _progressLabel = [[UILabel alloc]initWithFrame:self.bounds]; _progressLabel.textColor = cycle_green; _progressLabel.textAlignment = NSTextAlignmentCenter; _progressLabel.font = FontSize(18); [self addSubview:_progressLabel]; } return _progressLabel; } - (void)setPercent:(CGFloat)percent { _percent = percent; _percent = _percent > 100 ? 100 : _percent; _percent = _percent < 0 ? 0 : _percent; } - (UIBezierPath *)path { if (!_path) { CGFloat halfWidth = self.pathWidth / 2; _path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(halfWidth, halfWidth) radius:(self.pathWidth - self.lineWidth)/2 startAngle:-M_PI/2 endAngle:M_PI/2*3 clockwise:YES]; } return _path; } - (CGFloat)lineWidth { if (_lineWidth == 0) { _lineWidth = kSizeFrom750(8); } return _lineWidth; } @end