画饼状图四

添加了点击事件,添加了比例label。

头文件:

@class GY_PieChart;

@protocol GY_PieChartDelegete <NSObject>

- (void)pieChart:(GY_PieChart *)chart didSelectAtIndex:(NSInteger)index;

@end

实现文件:

#import "GY_PieChart.h"

@interface GY_PieChart ()

@property (nonatomic, assign) CGFloat startAngle;
@property (nonatomic, assign) CGFloat endAngle;

@property (nonatomic, strong) NSMutableArray *valuesAry;
@property (nonatomic, strong) NSMutableArray *colorsAry;
@property (nonatomic, strong) NSMutableArray * arcLayers;
@property (nonatomic, assign) CGFloat radius; //圆的半径

@property (nonatomic, assign) NSInteger currentArcIndex;  //用于标记当前播放到那个扇形了

@property (nonatomic, strong) NSMutableArray *endAges;
@property (nonatomic, assign) CGPoint centerPoint;

@end

@implementation GY_PieChart

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setBackgroundColor:[UIColor cyanColor]];
        _currentArcIndex = 0;
        _totalPlayTime = 1;
        _valuesAry = [[NSMutableArray alloc] initWithObjects:@"15",@"10",@"25",@"20",@"30", nil];
        _colorsAry = [[NSMutableArray alloc] initWithObjects:[UIColor blackColor],[UIColor yellowColor],[UIColor brownColor],[UIColor whiteColor],[UIColor darkGrayColor], nil];
        _arcLayers = [[NSMutableArray alloc] init];
        _endAges = [[NSMutableArray alloc] init];
        _radius = frame.size.width/2;
    }
    return self;
}

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}

#pragma mark - 动画

/**
 *  填充动画过程
 *
 *  @return CABasicAnimation
 */
- (CABasicAnimation *)animation {
    CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation.duration = [self cacaulatecurrentArcDuration];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = YES;
    animation.fromValue = @(0.f);
    animation.toValue = @(1.f);
    animation.delegate = self;
    return animation;
}

/**
 *  这是要绘制的扇形的路径,路径交给shapeLayer:去绘制扇形
 *
 *  @return UIBezierPath
 */
- (UIBezierPath *)fill {
    //需要多少度的圆弧
    CGPoint arcCenter = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
    UIBezierPath *_bezierpath = [UIBezierPath bezierPathWithArcCenter:arcCenter
                                                                radius:self.frame.size.width/4
                                                            startAngle:_startAngle
                                                              endAngle:_endAngle
                                                             clockwise:YES];
    return _bezierpath;
}

//制作扇形,添加动画
- (CAShapeLayer *)shapeLayer:(UIColor *)color {
    CAShapeLayer * layer = [CAShapeLayer layer];
    layer.fillColor = nil;
    layer.strokeColor = color.CGColor;
    layer.lineWidth = self.frame.size.width/2;
    layer.path = [self fill].CGPath;
    
    CABasicAnimation * animation = [self animation];
    [layer addAnimation:animation forKey:nil];
    return layer;
}

//移除绘制的扇形
- (void)removeAllSubLayers {
    for (CAShapeLayer * layer in _arcLayers) {
        [layer removeFromSuperlayer];
    }
    [_arcLayers removeAllObjects];
}

/**
 *  重绘,设置初始值
 */
- (void)strokePath {
    [self removeAllSubLayers];
    [_endAges removeAllObjects];
    _currentArcIndex = 0;
    _startAngle = -M_PI_2;
    [self strokeSinglePath];
}

/**
 *  重绘单个扇形,这里是准备绘制扇形的参数
 */
- (void)strokeSinglePath {
    _endAngle = _startAngle + [self cacaulatecurrentArcPercent]*M_PI*2;
    [_endAges addObject:[NSNumber numberWithFloat:_endAngle]];
    [self startStroke];
}

/**
 *  开始干活,绘制扇形添加到页面上,只管干活,判断什么的不用我管,给我什么我绘制什么
 */
- (void)startStroke {
    NSLog(@"do:%ld",_currentArcIndex);
    CAShapeLayer *layer = [self shapeLayer:[self.colorsAry objectAtIndex:_currentArcIndex]];
    [self.layer addSublayer:layer];
    [self.arcLayers addObject:layer];
}

/**
 *  是否是最后一个扇形,用于在绘制最后一个扇形时,设置endAngle
 */
- (BOOL)isLast {
    if (_currentArcIndex==[_valuesAry count]-1) {
        return YES;
    }
    return NO;
}

/**
 *  计算数组中数据的总和
 */
- (CGFloat)caculateValuesArySum {
    NSNumber *sumNumber = [_valuesAry valueForKeyPath:@"@sum.floatValue"];
    return [sumNumber floatValue];
}

/**
 *  计算每个扇形的数值占总数的比例
 */
- (CGFloat)cacaulatecurrentArcPercent {
    CGFloat valueF = [[_valuesAry objectAtIndex:_currentArcIndex] floatValue];
    CGFloat rate = valueF/[self caculateValuesArySum];
    return rate;
}

/**
 *  计算每个扇形绘制动画需要的时间,这里以画一圈圆需要1秒为默认值,每个扇形根据它自己数值的大小去分这1秒
 */
- (CGFloat)cacaulatecurrentArcDuration {
    NSLog(@"animition time: %f",[self cacaulatecurrentArcPercent]*_totalPlayTime);
    return [self cacaulatecurrentArcPercent]*_totalPlayTime;
}

/**
 *  这是我思想的核心,我的想法是当一个扇形的动画展示完毕,再去绘制下一个,知道结束
 */
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    if (flag) {
        [self creatPercentLabel];
        _startAngle = _endAngle;
        _currentArcIndex++;
        if (_currentArcIndex < [_valuesAry count]) {
            if ([self isLast]) {
                _endAngle = M_PI*0.75*2;
            }
            [self strokeSinglePath];
        }
    }
}

/**
 *  获取每个path的中心点,用于绘制每个扇形上的label
 *
 *  @return CGPoint
 */
- (CGPoint)getArcCenterPointWithStartAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle{
    NSLog(@"startAngle:%f,endAngle:%f",startAngle,endAngle);
    //一半角度(弧度)
    CGFloat halfAngle = (endAngle - startAngle) / 2;
    //中心角度(弧度)
    CGFloat centerAngle = halfAngle + startAngle;
    
    NSLog(@"centerAngle:%f",centerAngle);
    
    CGFloat center_xPos = cos(centerAngle) * _radius/2 + self.frame.size.width/2;
    CGFloat center_yPos = sin(centerAngle) * _radius/2 + self.frame.size.height/2;
    NSLog(@"%f,%f",center_xPos,center_yPos);
    return CGPointMake(center_xPos, center_yPos);
}

- (CGRect)string:(NSString *)str widthRectWithSize:(CGSize)size fontOfSize:(CGFloat)fontOfSize isBold:(BOOL)isBold{
    NSDictionary * attributes;
    if (isBold) {
        attributes = @{NSFontAttributeName: [UIFont boldSystemFontOfSize:fontOfSize]};
    } else {
        attributes = @{NSFontAttributeName: [UIFont systemFontOfSize:fontOfSize]};
    }
    
    return [str boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil];
}

/**
 *  添加百分比Label
 */
- (void)creatPercentLabel {
    NSString * string = [NSString stringWithFormat:@"pie:%ld",_currentArcIndex];
    CGRect rect = [self string:string widthRectWithSize:CGSizeMake(0, 0) fontOfSize:12 isBold:YES];
    UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, rect.size.width, rect.size.height)];
    label.text = string;
    label.textAlignment = NSTextAlignmentCenter;
    label.font = [UIFont boldSystemFontOfSize:12];
    label.center = [self getArcCenterPointWithStartAngle:_startAngle endAngle:_endAngle];
    label.tag = 1000 + _currentArcIndex;
    label.backgroundColor = [UIColor redColor];
    [self addSubview:label];
}

- (CGFloat)caculateAngleByTouchCircle:(CGPoint)center fromPoint:(CGPoint)reference {
    if (reference.x - center.x == 0) {
        return -M_PI_2;
    }
    //Find angle of line Passing In Reference And Center
    CGFloat angleOfLine = atanf((reference.y - center.y) / (reference.x - center.x));
    return (reference.x - center.x) > 0 ? angleOfLine : angleOfLine+M_PI;
}

- (CGFloat)endPercentageForItemAtIndex:(NSUInteger)index{
    return [_endAges[index] floatValue];
}

/*
 /  我点击了哪个扇形,怎么判断呢
 /  需要两个参数去对比,1.我点击的这个点的弧度angle 2.存放弧度的数组,用于计算我点击的这个点在哪个范围内
 /  其实根据这个原理还有其他的方法可行,比如得到我点击的这个点在圆中的角度后,就可以计算这个角度在圆中占有的比例,angle/M_PI*sum,sum是所有数据的总和,再跟
 /  _valuesAry中的数据对比也可以达到目的
 / return 当前点击的item的标记
*/
- (NSInteger)whitchItemITouched:(CGPoint)point {
    NSInteger index = 0;
    CGFloat myAngle = [self caculateAngleByTouchCircle:CGPointMake(self.frame.size.width/2, self.frame.size.height/2) fromPoint:point];
    while ((myAngle > [[_endAges objectAtIndex:index] floatValue]) && (index < [_valuesAry count])) {
        index++;
    }
    return index;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touche = [touches anyObject];
    NSInteger item = [self whitchItemITouched:[touche locationInView:self]];
//    CAShapeLayer *layer = [_arcLayers objectAtIndex:item];
//    layer.frame = CGRectMake(layer.frame.origin.x+5, layer.frame.origin.y, layer.frame.size.width, layer.frame.size.height);
    if ([self.delegate respondsToSelector:@selector(pieChart:didSelectAtIndex:)]) {
        [self.delegate pieChart:self didSelectAtIndex:item];
    }
}

@end



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值