iOS仿支付宝账单饼状图

作者: 退役程序猿 | 来源:发表于2017-03-07 10:29 被阅读925次

    前言:

    • 这段时间项目做了一个账单查询的页面使用到了饼状图,支付宝账单那个饼状图,就简单的封装了一个给大家看看,使用的基本技术也就是使用UIBezierPath绘制柱状图路径,再把CAShapeLayer和UIBezierPath建立关系,最后使用CABasicAnimation实现简单的动画效果。

    先看下效果图:动画太快了注意看吧

    Untitled.gif

    1.绘制饼状图

    绘制饼状图计算每个扇形弧度中心点坐标记录成员变量给指示线起点&指示线起点圆点使用

    #pragma mark ------ 绘制饼状图 -------
    - (void)addPieChart:(CAShapeLayer *)layer
           andArcCenter:(CGPoint)ArcCenter
         andStart_Angle:(CGFloat)start_Angle
           andend_Angle:(CGFloat)end_Angle
       andPieChartWidht:(CGFloat)PieChartWidht
    andandPieChartColor:(UIColor *)andPieChartColor{
    
        UIBezierPath * progressPath = [UIBezierPath bezierPathWithArcCenter:ArcCenter radius:PieChartRadius startAngle:DEGREES_TO_VALUE(start_Angle) endAngle:DEGREES_TO_VALUE(end_Angle) clockwise:YES];
        layer.path = progressPath.CGPath;
        layer.lineWidth = PieChartWidht;
        layer.strokeColor = andPieChartColor.CGColor;
    
        // 计算存储圆弧中心点到数组
        // 弧度的中心角度
        CGFloat RadianCentreCoordinate = (DEGREES_TO_VALUE(start_Angle) + DEGREES_TO_VALUE(end_Angle)) / 2.0;
    
        // 记录小圆的中心点(折现起始点)
        ArcCentreCoordinate.x = ArcCenter.x+(PieChartRadius+40) * cos(RadianCentreCoordinate);
        ArcCentreCoordinate.y = ArcCenter.y+(PieChartRadius+40) * sin(RadianCentreCoordinate);
    }
    

    2.饼状图动画添加

    饼状图绘制是基于UIBezierPath所有添加动画使用CABasicAnimation

    #pragma mark ------ 饼状图动画添加 -------
    - (void)addPieChart:(CAShapeLayer *)layer
           andArcCenter:(CGPoint)ArcCenter
         andStart_Angle:(CGFloat)start_Angle
           andend_Angle:(CGFloat)end_Angle
       andPieChartWidht:(CGFloat)PieChartWidht
       andPieChartColor:(UIColor *)PieChartColor
               animated:(BOOL)animated{
    
        [self addPieChart:layer andArcCenter:ArcCenter andStart_Angle:start_Angle andend_Angle:end_Angle andPieChartWidht:PieChartWidht andandPieChartColor:PieChartColor];
    
        CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    
        pathAnimation.duration = end_Angle*0.01;
    
        pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
    
        pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
    
        [layer addAnimation:pathAnimation forKey:nil];
    }
    

    3.绘制指示线

    这个指示线挺烦,坐标系原理你们自己看看吧。

    #pragma mark ------ 绘制指示线 -------
    - (CGPoint)addIndicatrixLine:(CAShapeLayer *)layer
          andOriginCoordinate:(CGPoint)OriginCoordinate
      andIndicatrixLineLength:(CGFloat)IndicatrixLineLength
       andIndicatrixLineWidth:(CGFloat)IndicatrixLineWidth
       andIndicatrixLineColor:(UIColor *)IndicatrixLineColor{
        
        //起点坐标
        CGFloat IndicatrixLine_Origin_CoordInateX = OriginCoordinate.x;
        CGFloat IndicatrixLine_Origin_CoordInateY = OriginCoordinate.y;
    
        //圆点坐标
        [self addIndicatrixLine_Origin_Style:CGPointMake(IndicatrixLine_Origin_CoordInateX, IndicatrixLine_Origin_CoordInateY) andColor:IndicatrixLineColor];
    
        //终点坐标
        CGFloat IndicatrixLine_End_CoordInateX;
        CGFloat IndicatrixLine_End_CoordInateY;
    
        UIBezierPath * IndicatrixLine = [UIBezierPath bezierPath];
    
        //指示线第一段(小段)
        if (IndicatrixLine_Origin_CoordInateX < ARCCENTER.x) {
    
            if (IndicatrixLine_Origin_CoordInateY < ARCCENTER.y) {
    
                //终点坐标
                IndicatrixLine_End_CoordInateX = OriginCoordinate.x-10;
                IndicatrixLine_End_CoordInateY = OriginCoordinate.y-10;
            }else{
    
                //终点坐标
                IndicatrixLine_End_CoordInateX = OriginCoordinate.x-10;
                IndicatrixLine_End_CoordInateY = OriginCoordinate.y+10;
            }
        }else{
    
            if (IndicatrixLine_Origin_CoordInateY < ARCCENTER.y) {
    
                //终点坐标
                IndicatrixLine_End_CoordInateX = OriginCoordinate.x+10;
                IndicatrixLine_End_CoordInateY = OriginCoordinate.y-10;
            }else{
    
                //终点坐标
                IndicatrixLine_End_CoordInateX = OriginCoordinate.x+10;
                IndicatrixLine_End_CoordInateY = OriginCoordinate.y+10;
            }
        }
    
        [IndicatrixLine moveToPoint:CGPointMake(IndicatrixLine_Origin_CoordInateX, IndicatrixLine_Origin_CoordInateY)];
        [IndicatrixLine addLineToPoint:CGPointMake(IndicatrixLine_End_CoordInateX, IndicatrixLine_End_CoordInateY)];
    
        //画完第一段(小段)把小段的终点赋值给第二段(大段)当起点
        IndicatrixLine_Origin_CoordInateX = IndicatrixLine_End_CoordInateX;
        IndicatrixLine_Origin_CoordInateY = IndicatrixLine_End_CoordInateY;
    
        //指示线第二段(大段)
        if (IndicatrixLine_Origin_CoordInateX < ARCCENTER.x) {
    
            if (IndicatrixLine_Origin_CoordInateY < ARCCENTER.y) {
    
                //终点坐标
                IndicatrixLine_End_CoordInateX = OriginCoordinate.x-IndicatrixLineLength;
                IndicatrixLine_End_CoordInateY = OriginCoordinate.y-10;
            }else{
    
                //终点坐标
                IndicatrixLine_End_CoordInateX = OriginCoordinate.x-IndicatrixLineLength;
                IndicatrixLine_End_CoordInateY = OriginCoordinate.y+10;
            }
    
        }else{
    
            if (IndicatrixLine_Origin_CoordInateY < ARCCENTER.y) {
    
                //终点坐标
                IndicatrixLine_End_CoordInateX = OriginCoordinate.x+IndicatrixLineLength;
                IndicatrixLine_End_CoordInateY = OriginCoordinate.y-10;
            }else{
    
                //终点坐标
                IndicatrixLine_End_CoordInateX = OriginCoordinate.x+IndicatrixLineLength;
                IndicatrixLine_End_CoordInateY = OriginCoordinate.y+10;
            }
        }
    
        [IndicatrixLine moveToPoint:CGPointMake(IndicatrixLine_Origin_CoordInateX, IndicatrixLine_Origin_CoordInateY)];
        [IndicatrixLine addLineToPoint:CGPointMake(IndicatrixLine_End_CoordInateX, IndicatrixLine_End_CoordInateY)];
    
        layer.path = IndicatrixLine.CGPath;
        layer.lineWidth = IndicatrixLineWidth;
        layer.strokeColor = IndicatrixLineColor.CGColor;
    
        return CGPointMake(IndicatrixLine_End_CoordInateX, IndicatrixLine_End_CoordInateY);
    }
    

    4.指示线添加动画

    和饼状图动画添加是一样的

    #pragma mark ------ 指示线动画添加 -------
    - (CGPoint)addIndicatrixLine:(CAShapeLayer *)layer
          andOriginCoordinate:(CGPoint)OriginCoordinate
      andIndicatrixLineLength:(CGFloat)IndicatrixLineLength
       andIndicatrixLineWidth:(CGFloat)IndicatrixLineWidth
       andIndicatrixLineColor:(UIColor *)IndicatrixLineColor
                     animated:(BOOL)animated{
    
       CGPoint TextCoordinate = [self addIndicatrixLine:layer andOriginCoordinate:OriginCoordinate andIndicatrixLineLength:IndicatrixLineLength andIndicatrixLineWidth:IndicatrixLineWidth andIndicatrixLineColor:IndicatrixLineColor];
    
        CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    
        pathAnimation.duration = IndicatrixLineLength*0.01;
    
        pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
    
        pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
    
        [layer addAnimation:pathAnimation forKey:nil];
    
        return TextCoordinate;
    }
    

    5.指示线起点样式

    这个是绘制了一个小圆点作为指示线起点

    #pragma mark ------ 绘制指示线起点样式 -------
    - (void)addIndicatrixLine_Origin_Style:(CGPoint)coordinate
    
                              andColor:(UIColor *)indicatrixLineColor{
    
        CAShapeLayer *circleLayer = [CAShapeLayer layer];
        // 指定frame,只是为了设置宽度和高度
        circleLayer.frame = CGRectMake(0, 0, 2, 2);
        // 设置居中显示
        circleLayer.position = CGPointMake(coordinate.x, coordinate.y);
        // 设置填充颜色
        circleLayer.fillColor = [UIColor clearColor].CGColor;
        // 设置线宽
        circleLayer.lineWidth = 2.0;
        // 设置线的颜色
        circleLayer.strokeColor = indicatrixLineColor.CGColor;
    
        // 使用UIBezierPath创建路径
        CGRect frame = CGRectMake(0, 0, 2, 2);
        UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:frame];
    
        // 设置CAShapeLayer与UIBezierPath关联
        circleLayer.path = circlePath.CGPath;
    
        // 将CAShaperLayer放到某个层上显示
        [self.layer addSublayer:circleLayer];
    }
    

    5.指示线上下文字绘制

    指示线上下文字绘制这个么什么好说的

    #pragma mark ------ 绘制指示文字 -------
    - (void)addHintText:(CGPoint)TextCoordinate
           andabovetext:(NSString *)abovetext
            andDowntext:(NSString *)Downtext
            andTextFont:(CGFloat)font
           andTextColor:(UIColor *)color{
    
        // 上面Size
        CGSize abovetextSize = [abovetext sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:font]}];
        // 下面Size
        CGSize DowntextSize = [Downtext sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:font]}];
    
        //上面文字坐标
        CGFloat abovetextCoordinateX;
        CGFloat abovetextCoordinateY;
        //下面文字坐标
        CGFloat DowntextCoordinateX;
        CGFloat DowntextCoordinateY;
    
        if (ARCCENTER.x < TextCoordinate.x) {
    
            abovetextCoordinateX = TextCoordinate.x-abovetextSize.width;
            abovetextCoordinateY = TextCoordinate.y-abovetextSize.height;
    
            DowntextCoordinateX = TextCoordinate.x-DowntextSize.width;
            DowntextCoordinateY = TextCoordinate.y;
        }else{
    
            abovetextCoordinateX = TextCoordinate.x;
            abovetextCoordinateY = TextCoordinate.y-abovetextSize.height;
    
            DowntextCoordinateX = TextCoordinate.x;
            DowntextCoordinateY = TextCoordinate.y;
        }
    
        NSMutableParagraphStyle * paragraph = [[NSMutableParagraphStyle alloc]init];
        paragraph.alignment = NSTextAlignmentLeft;
    
        //指引线上面的数字
        [abovetext drawAtPoint:CGPointMake(abovetextCoordinateX, abovetextCoordinateY) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:font],NSForegroundColorAttributeName:color,NSParagraphStyleAttributeName:paragraph}];
        //指示线下面的文字
        [Downtext drawAtPoint:CGPointMake(DowntextCoordinateX, DowntextCoordinateY)
    
                        withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:font],
                                         NSForegroundColorAttributeName:color,
                                         NSParagraphStyleAttributeName:paragraph}];
    
    }
    

    6. drawRect绘制调用

        - (void)drawRect:(CGRect)rect {
            // Drawing code
    
            NSArray * RedAarray = @[@"46",@"255",@"62",@"254",@"253",@"153",@"110"];
            NSArray * greenArray = @[@"191",@"48",@"209",@"199",@"109",@"208",@"123"];
            NSArray * blueArray = @[@"238",@"145",@"185",@"17",@"31",@"60",@"254"];
    
            for (int i = 0; i < _ArcCentreCoordinateAll.count; i++) {
    
                CAShapeLayer * progressLayer = [CAShapeLayer new];
                [self.layer addSublayer:progressLayer];
                progressLayer.fillColor = nil;
                progressLayer.frame = self.bounds;
    
                end = start+[[_ArcCentreCoordinateAll objectAtIndex:i] floatValue];
    
                NSMutableArray * startORendArray =  [[NSMutableArray alloc]init];
                [startORendArray addObject:[NSString stringWithFormat:@"%f",start]];
                [startORendArray addObject:[NSString stringWithFormat:@"%f",end]];
    
                start = end;
    
                /*
                 @1.addPieChart:CAShapeLayer对象
                 @2.andArcCenter:饼状图中心坐标
                 @3.andStart_Angle:饼状图起点位置
                 @4.andend_Angle:饼状图结束点位置
                 @5.andPieChartColor:饼状图颜色
                 @6.animated:是否添加动画
                 */
    
                [self addPieChart:progressLayer
                     andArcCenter:ARCCENTER
                   andStart_Angle:[startORendArray[0] floatValue]
                     andend_Angle:[startORendArray[1] floatValue]
                 andPieChartWidht:_PieChartWidth
                 andPieChartColor:[UIColor colorWithRed:[[RedAarray objectAtIndex:i] intValue]/255.0  green:[[greenArray objectAtIndex:i] intValue]/255.0 blue:[[blueArray objectAtIndex:i] intValue]/255.0 alpha:1]
    
                 animated:YES];
    
                CAShapeLayer * IndicatrixLayer =  [CAShapeLayer new];
                [self.layer addSublayer:IndicatrixLayer];
                IndicatrixLayer.fillColor = nil;
                IndicatrixLayer.frame = self.bounds;
    
                /*
                 @1.addIndicatrixLine:CAShapeLayer对象
                 @2.andOriginCoordinate:指示线&线帽起点坐标
                 @3.andIndicatrixLineLength:指示线长度
                 @4.andIndicatrixLineLength:指示线宽度
                 @5.andIndicatrixLineColor:指示线颜色
                 @6.animated:是否添加动画
                 */
    
                CGPoint TextCoordinate =  [self addIndicatrixLine:IndicatrixLayer
    
            andOriginCoordinate:ArcCentreCoordinate
        andIndicatrixLineLength:_IndicatrixLineLength
         andIndicatrixLineWidth:_IndicatrixLineWidth
         andIndicatrixLineColor:[UIColor colorWithRed:[[RedAarray objectAtIndex:i] intValue]/255.0  green:[[greenArray objectAtIndex:i] intValue]/255.0 blue:[[blueArray objectAtIndex:i] intValue]/255.0 alpha:1]
                       animated:YES];
    
                /*
                 @1.addHintText:文字坐标
                 @2.andabovetext:上面文字
                 @3.andDowntext:下面文字
                 @4.andTextFont:文字大小
                 @5.andTextColor:文字颜色
                 */
    
                [self addHintText:TextCoordinate
    
             andabovetext:_aboveHintTextAttayAll[i]
              andDowntext:_belowHintTextAttayAll[i]
              andTextFont:_HintTextFont
             andTextColor:_HintTextColor];
    
            }
        }
    

    相关文章

      网友评论

      • 伽马星人:厉害厉害
        退役程序猿:@伽马星人 彼此彼此
      • aliasenor:有安卓版本的么?
        退役程序猿:@aliasenor 没有 。:cold_sweat:
      • 30baf1b4df5c:不错 给饼图上加了几个图标
        退役程序猿:多谢 图标的话项目没有需求 我就么做了 以后有时间会更新一下。。 这个有一个比例问题 如果俩个小比例挨着 会照成 指示线重叠 这个我看支付宝那个饼图是比例小得都处理了(把小比例的增加了一定量) 我这么没有处理,是后端给数据的时候处理了。。
      • 0715c4bee8ac:现在这个圆的大小是固定的吧,如何改变整个圆的大小(比如说我要改变中间圆圈的大小,外边各个部分不变,那如何改变整个圆的大小那)
        退役程序猿:可以改,在绘制饼状图那个方法中 修改radius 和PieChartWidht 就可以调整饼的大小和空心的大小
      • 我是你男神啊MyLady:吊吊吊:smirk::smirk::smirk:膜拜了
        退役程序猿:感谢支持。。
      • 366c628ae6e7:哎哟,不错哟
        退役程序猿:谢谢,谢谢

      本文标题:iOS仿支付宝账单饼状图

      本文链接:https://www.haomeiwen.com/subject/uxgapttx.html