277 lines
8.9 KiB
Objective-C
Executable File
277 lines
8.9 KiB
Objective-C
Executable File
//
|
|
// HKPieChartView.m
|
|
// PieChart
|
|
//
|
|
// Created by hukaiyin on 16/6/20.
|
|
// Copyright © 2016年 HKY. All rights reserved.
|
|
//
|
|
|
|
#import "HKPieChartView.h"
|
|
#define Cycle_DarkBlue RGB(0, 150, 200)
|
|
#define Cycle_LightBlue RGB(160, 200, 255)
|
|
@interface HKPieChartView()<CAAnimationDelegate>
|
|
|
|
@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 = [UIColor clearColor];
|
|
self.progressColor = Cycle_DarkBlue;
|
|
self.animationDuration = 1;
|
|
self.pathWidth = self.frame.size.width - kSizeFrom750(8);
|
|
|
|
[self shadowImageView];
|
|
[self trackLayer];
|
|
[self gradientLayer];
|
|
[self loadGesture];
|
|
}
|
|
- (void)endProgressWithString:(NSString *)text{
|
|
self.progressLabel.text = text;
|
|
}
|
|
- (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.f);
|
|
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.progressLabel.text = @"设备连接中...";
|
|
|
|
}
|
|
|
|
- (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
|
|
{
|
|
NSLog(@"%.2f",progress);
|
|
self.progressLabel.text = [NSString stringWithFormat:@"%.0f%%",floorf(progress * 100)];
|
|
if (progress>0.5) {
|
|
[self updatePercent:100 animation:NO];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- (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_LightBlue 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.colors = @[(id)Cycle_DarkBlue.CGColor,(id)HEXCOLOR(@"#3b82f6").CGColor];
|
|
_gradientLayer.colors = @[(id)Cycle_DarkBlue.CGColor,(id)Cycle_DarkBlue.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_DarkBlue;
|
|
_progressLabel.textAlignment = NSTextAlignmentCenter;
|
|
_progressLabel.font = FontSize(14);
|
|
_progressLabel.text = @"设备连接中...";
|
|
[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
|