iOS利用贝塞尔曲线和CAShapeLayer创建纵向分段颜色带动画柱状图

前言

  • 最近项目中要求使用柱状图来显示数据,但是要求在柱子上显示不同的颜色,查找了很多第三方的库,然而并没有找到合适的,无奈之下只好自己进行封装.
  • 参考资料
    http://blog.csdn.net/nb_killer/article/details/51023948
    http://www.cnblogs.com/nightcat/p/ios_01.html
    PNChart 库

效果图

  • 柱子的高度是到顶部的,由于柱子的颜色和View背景色一致了,无法看清,更改下背景色就能看到了,柱子的最大值是1440,可以根据自己需求进行更改 这个属性 MAX_TIME
iOS利用贝塞尔曲线和CAShapeLayer创建纵向分段颜色带动画柱状图_第1张图片
![MKChart.gif](http://upload-images.jianshu.io/upload_images/2597026-70c5424b0f14cbef.gif)
  • 本文主要参考了PNChart ,有兴趣的同学可以去学习下
    废话不说了,直接上代码

  • 主要分为3个类

  • MKBar: 是单个柱子,包括绘制和数据的分段处理

  • BarLayerView : 主要是绘制多个柱子,对柱子进行更新等

  • ViewController : 展示界面

MKBar

MKBar.h

#import 

@interface MKBar : UIView

@property (nonatomic,copy)NSString *titleStr;//标题

@property (nonatomic,strong)NSMutableArray *dataArr;//数据  注意数据格式

@end

MKBar.m

#define MAX_TIME 1440
#define RGB(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
@interface MKBar ()

@property (nonatomic) CATextLayer* textLayer;//标题Layer

@property (nonatomic,strong)NSMutableArray *barArr;//柱子上面进度数据

@property (nonatomic,assign)float totalNum;//总的进度时间

@property (nonatomic,strong)UILabel *titleLab;//下面标题  也可以使用CATextLayer

@end

@implementation MKBar

-(instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
    {
        
        
    }
    return self;
}
-(void)setTitleStr:(NSString *)titleStr
{
    _titleStr = titleStr;
    [self addSubview:self.titleLab];
    
    
    //CABasicAnimation *fade = [self fadeAnimation];
    //[self.textLayer addAnimation:fade forKey:nil];
    //[self.layer addSublayer:self.textLayer];
    
}

-(void)setDataArr:(NSMutableArray *)dataArr
{
    _dataArr = dataArr;
    
    self.barArr = [self barProgressArr:_dataArr];
    
    [self setProgress];
    
}
#pragma mark ---画图
-(void)setProgress
{
    __block float a = 0;
    //遍历数组
    [self.barArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        //画路径
        UIBezierPath *beziPath = [UIBezierPath bezierPath];
        beziPath.lineWidth = 0.0;//线的宽度
        //起点坐标
        
        [beziPath moveToPoint:CGPointMake(15,self.bounds.size.height-20)];
        //终点坐标
        [beziPath addLineToPoint:CGPointMake(15,(MAX_TIME-self.totalNum)/MAX_TIME*(self.bounds.size.height-20))];
        beziPath.lineCapStyle = kCGLineCapRound;
        beziPath.lineJoinStyle = kCGLineJoinRound;
        [beziPath stroke];
        
        //画图
        CAShapeLayer *shapeLayer = [CAShapeLayer layer];
        shapeLayer.fillColor = [UIColor clearColor].CGColor;
        shapeLayer.strokeColor = [obj[@"strokeColor"]CGColor];
        shapeLayer.lineWidth = 30.0;//宽度 目前是固定宽度 可以根据情况进行修改
        shapeLayer.strokeStart = a;//起始点
        shapeLayer.strokeEnd = [obj[@"precent"] floatValue]+a;//结束点
        a = shapeLayer.strokeEnd;//从上一个起始点开始画图
        shapeLayer.path = beziPath.CGPath;//产生联系
        
        [self.layer addSublayer:shapeLayer];
        
        
        //动画
        CABasicAnimation*pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        pathAnimation.duration=1.0f;
        pathAnimation.timingFunction= [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        [email protected];
        pathAnimation.toValue=@(1);
        [shapeLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
        
        
    }];

    
    
}
#pragma mark ---处理进度数据
-(NSMutableArray *)barProgressArr:(NSMutableArray *)dataArr
{
    NSMutableArray *barProgArr = [[NSMutableArray alloc]initWithCapacity:0];
    
    self.totalNum = 0.0;//总的时间
    float value = 0.0;//每一段时间
    NSString *boolStr;
    //计算总时间
    for (NSDictionary *dic in dataArr)
    {
        value = [dic[@"precent"] floatValue];
        
        self.totalNum = self.totalNum + value;
    }
    
    //计算进度值
    for (NSDictionary *dic in dataArr)
    {
        value = [dic[@"precent"] floatValue];
        
        boolStr = dic[@"strokeColor"];
        
        NSMutableDictionary *progDic = [[NSMutableDictionary alloc]initWithCapacity:0];
        
        //根据BOOL确定颜色  当然也可以添加多种颜色
        if ([boolStr isEqualToString:@"1"])
        {
            [progDic setObject:[UIColor redColor] forKey:@"strokeColor"];
        }
        else
        {
            [progDic setObject:RGB(83, 193, 124) forKey:@"strokeColor"];
        }
        
        //计算进度 添加进数组
        [progDic setObject:@(value/self.totalNum) forKey:@"precent"];
        
        [barProgArr addObject:progDic];
        
    }
    
    return barProgArr;
}
-(UILabel *)titleLab
{
    if (!_titleLab)
    {
        _titleLab = [[UILabel alloc]initWithFrame:CGRectMake(0, self.bounds.size.height-20, self.bounds.size.width, 20)];
        _titleLab.font = [UIFont systemFontOfSize:14.0];
        _titleLab.textAlignment = NSTextAlignmentCenter;
        _titleLab.textColor = [UIColor whiteColor];
        _titleLab.text = self.titleStr;
        
    }
    return _titleLab;
}
#pragma mark ---可以使用CATextLayer
-(CATextLayer*)textLayer
{
    if (!_textLayer) {
        _textLayer = [[CATextLayer alloc]init];
        _textLayer.string = self.titleStr;
        _textLayer.frame = CGRectMake(0, self.bounds.size.height-20, self.bounds.size.width, 20);
        [_textLayer setAlignmentMode:kCAAlignmentCenter];
        [_textLayer setForegroundColor:[[UIColor whiteColor] CGColor]];

        _textLayer.fontSize = 14.0;
    }
    
    return _textLayer;
}
//动画
-(CABasicAnimation*)fadeAnimation
{
    CABasicAnimation* fadeAnimation = nil;
    fadeAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    fadeAnimation.fromValue = [NSNumber numberWithFloat:0.0];
    fadeAnimation.toValue = [NSNumber numberWithFloat:1.0];
    fadeAnimation.duration = 2.0;
    return fadeAnimation;
}

BarLayerView

BarLayerView.h

#import 

@interface BarLayerView : UIView


@property (nonatomic,strong)NSMutableArray *xArr;//X轴数据

@property (nonatomic,strong)NSMutableArray *dataArr;//进度数据

@property (nonatomic,strong)NSMutableArray *barArr;//存放柱子的数组  用来删除

-(void)strokeMKBarChart;//绘制

@end

BarLayerView.m

#import "BarLayerView.h"
#import "MKBar.h"

#define RGB(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
@implementation BarLayerView


-(instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
    {
        self.barArr = [[NSMutableArray alloc]initWithCapacity:0];
        
        
    }
    return self;
}
-(void)setXArr:(NSMutableArray *)xArr
{
    _xArr = xArr;
}
-(void)setDataArr:(NSMutableArray *)dataArr
{
    _dataArr = dataArr;
}

-(void)strokeMKBarChart
{
    //删除所有的柱子
    [self viewCleanupForCollection:self.barArr];
    [self upDateMKBarChart];
}
//绘图
-(void)upDateMKBarChart
{
    
    CGFloat barInterval = (self.bounds.size.width-(30*(self.xArr.count+1)))/(self.xArr.count-1);
    
    for (int a = 0; a < self.xArr.count; a++)
    {
        
        MKBar *bar = [[MKBar alloc]initWithFrame:CGRectMake(10+(barInterval+30)*a, 0, 30, self.bounds.size.height)];
        bar.backgroundColor = RGB(54, 63, 86);
        [bar setDataArr:self.dataArr[a]];
        [bar setTitleStr:self.xArr[a]];
        
        [self.barArr addObject:bar];//添加进数组中,重绘时删除,重新创建
        
        [self addSubview:bar];
        
        
    }
    
    
}
//删除所有的柱子
- (void)viewCleanupForCollection:(NSMutableArray *)array
{
    if (array.count) {
        [array makeObjectsPerformSelector:@selector(removeFromSuperview)];
        [array removeAllObjects];
    }
}



ViewController

#import "ViewController.h"
#import "BarLayerView.h"
#import "MKBar.h"

#define RGB(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
@interface ViewController ()

@property (nonatomic,strong)CAShapeLayer *shapeLayer;

@property (nonatomic,strong)BarLayerView *barLayerView;

@end


- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    //测试数据
    //单个柱子上的分段数据
    NSMutableArray *arr = [[NSMutableArray alloc]initWithCapacity:0];
    //需要展示几段
    [arr addObject:@{@"precent":@"200",@"strokeColor":@"1"}];
    [arr addObject:@{@"precent":@"100",@"strokeColor":@"0"}];
    [arr addObject:@{@"precent":@"200",@"strokeColor":@"1"}];
    [arr addObject:@{@"precent":@"300",@"strokeColor":@"0"}];
    [arr addObject:@{@"precent":@"200",@"strokeColor":@"1"}];
    
    //柱子个数
    NSMutableArray *dataArr = [[NSMutableArray alloc]initWithCapacity:0];
    
    [dataArr addObject:arr];
    [dataArr addObject:arr];
    [dataArr addObject:arr];
    [dataArr addObject:arr];
    [dataArr addObject:arr];
    [dataArr addObject:arr];
    [dataArr addObject:arr];
    
    //X轴数据
    NSMutableArray *xArr = [[NSMutableArray alloc]initWithCapacity:0];
    [xArr addObject:@"1"];
    [xArr addObject:@"2"];
    [xArr addObject:@"3"];
    [xArr addObject:@"4"];
    [xArr addObject:@"5"];
    [xArr addObject:@"6"];
    [xArr addObject:@"7"];
    
    self.barLayerView = [[BarLayerView alloc]initWithFrame:CGRectMake(00, 100, self.view.bounds.size.width, 200)];
    
    self.barLayerView.backgroundColor = RGB(54, 63, 86);
    [self.barLayerView setDataArr:dataArr];//设置柱子进度
    
    [self.barLayerView setXArr:xArr];//设置XLable
    
    [self.barLayerView strokeMKBarChart];//重绘
    
    [self.view addSubview:self.barLayerView];
    
}

当然Demo也有许多需要更改的地方,比如固定的宽度等等

如果感觉对您有帮助,请顺手点个赞,哈哈....

原创文章,如果转载,请注明出处,谢谢.

你可能感兴趣的:(iOS利用贝塞尔曲线和CAShapeLayer创建纵向分段颜色带动画柱状图)