美文网首页Charts图表CALayeriOS开发
再简单不过的折线图实现方法

再简单不过的折线图实现方法

作者: little曾 | 来源:发表于2016-12-14 16:36 被阅读0次

    涉及知识点:

    CGContextRef    //  联系图形上下文,可以说是画布的存在吧

    UIBezierPath     //  贝塞尔曲线,画啥都可以,没有画不了的,只有想不到的

    CAShapeLayer    //  配合贝塞尔曲线使用的shape图层,贝塞尔的“最佳搭档”

    CAGradientLayer    //  渐变图层

    CABasicAnimation    // (基础)Core Animation 显示动画

    最近想弄一下比较实在的东西,然后有个朋友跟我说:“要不你就弄弄贝塞尔吧”。搞就搞吧,只有贝塞尔的话就有点单调,干脆就加点其他东西实现个简单的折线图吧,所以这个demo就出来了,不过这仅仅是小demo,完整的版本还没写好封装。话不多说,整个demo分四步:第一步,实现横、轴坐标轴;第二步,虚线与渐变层的实现;第三步,描点连线。直接上图贴代码,简单快捷。


    第一步  X 、Y轴的实现

    直接上第一张图


    X 、Y轴的实现

    创建一个类,继承于UIView,在.m文件中的- (void)drawRect:(CGRect)rect 方法中画出我们所需要的X轴Y轴坐标线。在这个方法中,我们所实现的视图能够在view上重新描画展示。

    - (void)drawRect:(CGRect)rect {

    // Drawing code

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 2.0);
    CGContextSetRGBStrokeColor(context, 97/255.0, 150/255.0, 198/255.0, 1);
    CGContextMoveToPoint(context, boundX, boundY);
    // Y 轴
    CGContextAddLineToPoint(context, boundX, rect.size.height - boundY);
    // X 轴
    CGContextAddLineToPoint(context, rect.size.width -  boundX, rect.size.height - boundY);
    // X轴 箭头
    CGContextMoveToPoint(context, rect.size.width -  boundX - 5, rect.size.height - boundY -5);
    CGContextAddLineToPoint(context, rect.size.width -  boundX, rect.size.height - boundY);
    CGContextAddLineToPoint(context, rect.size.width -  boundX - 5, rect.size.height - boundY + 5);
    // Y轴 箭头
    CGContextMoveToPoint(context, boundX - 5, boundY + 5);
    CGContextAddLineToPoint(context, boundX, boundY);
    CGContextAddLineToPoint(context, boundX + 5, boundY + 5);
    // 结束绘制
    CGContextStrokePath(context);
    }

    X轴与Y轴的数据实现,在这里分别写了两个实例方法,在initWithFram:初始化方法中调用

    #pragma mark 创建x轴的数据

    - (void)createXLine{

    CGFloat  month = 12;

    for (NSInteger i = 0; i < month; i++) {

    UILabel * x_label = [[UILabel alloc]initWithFrame:CGRectMake((self.frame.size.width - 2 * boundX)/month * i + boundX, self.frame.size.height - boundY + boundY*0.2, (self.frame.size.width - 2 * boundX)/month- 5, boundY/2)];

    //      LabelMonth.backgroundColor = [UIColor greenColor];

    x_label.tag = 1000 + i;

    x_label.text = [NSString stringWithFormat:@"%ld月",i+1];

    x_label.font = [UIFont systemFontOfSize:8];

    x_label.transform = CGAffineTransformMakeRotation(M_PI * 0.3);

    x_label.textColor = [UIColor whiteColor];

    [self addSubview:x_label];

    }

    }

    #pragma mark 创建y轴数据

    - (void)createYLine{

    CGFloat Y_Value = 6;

    for (NSInteger i = 0; i < Y_Value; i++) {

    UILabel * y_label = [[UILabel alloc]initWithFrame:CGRectMake(0, (self.frame.size.height - 2 * boundY)/Y_Value * i + boundX, boundY, boundY/2.0)];

    //  labelYdivision.backgroundColor = [UIColor greenColor];

    y_label.tag = 2000 + i;

    y_label.text = [NSString stringWithFormat:@"%.0f",(Y_Value - i)*100];

    y_label.font = [UIFont systemFontOfSize:10];

    y_label.textColor = [UIColor whiteColor];

    y_label.textAlignment = NSTextAlignmentCenter;

    [self addSubview:y_label];

    }

    }

    第二步  虚线与渐变图层背景的设置

    在这里我们需要设置三个属性,分别是:1.渐变的背景视图(添加到当前视图上), 2.渐变图层(作用于背景视图的layer层),3.颜色数组(添加渐变图层的颜色属性数值,也就是渐变哪几种颜色,这里我用了两种比较低调灰沉一点的色调)

    有一点要注意的是,我这里画的虚线是通过CAShapeLayer的 lineDashPattern属性来设置的

    属性

    同样编写两个方法:- (void)drawGradientBackgroundView 设置渐变层背景  和 - (void)setDashLine 设置虚线,并在初始化方法中调用

    - (void)drawGradientBackgroundView {

    // 渐变背景视图(不包含坐标轴)

    self.gradient_backgroundView = [[UIView alloc] initWithFrame:CGRectMake(boundX, boundY, self.bounds.size.width - boundX*2, self.bounds.size.height - 2*boundY)];

    [self addSubview:self.gradient_backgroundView];

    /** 创建并设置渐变背景图层 */

    //初始化CAGradientlayer对象,使它的大小为渐变背景视图的大小

    self.gradient_layer = [CAGradientLayer layer];

    self.gradient_layer.frame = self.gradient_backgroundView.bounds;

    //设置渐变区域的起始和终止位置(范围为0-1),即渐变路径

    self.gradient_layer.startPoint = CGPointMake(0, 0.0);

    self.gradient_layer.endPoint = CGPointMake(1.0, 0.0);

    //设置颜色的渐变过程

    // [UIColor colorWithRed:67 / 255.0 green:106 / 255.0 blue:140 / 255.0 alpha:1.0]

    // [UIColor colorWithRed:59 / 255.0 green:92 / 255.0 blue:120 / 255.0 alpha:1.0]

    self.colors_arr = [NSMutableArray arrayWithArray:@[(__bridge id)[UIColor colorWithRed:95 / 255.0 green:148 / 255.0 blue:195 / 255.0 alpha:0.4].CGColor, (__bridge id)[UIColor colorWithRed:59 / 255.0 green:92 / 255.0 blue:120 / 255.0 alpha:0.4].CGColor]];

    self.gradient_layer.colors = self.colors_arr;

    //将CAGradientlayer对象添加在我们要设置背景色的视图的layer层

    [self.gradient_backgroundView.layer addSublayer:self.gradient_layer];

    }

    - (void)setDashLine{

    for (NSInteger i = 1;i < 6; i++ ) {

    UILabel * label1 = (UILabel*)[self viewWithTag:2000 + i];//获取Y轴数据label的位置根据其位置画横虚线

    UIBezierPath * path1 = [UIBezierPath bezierPath];

    [path1 moveToPoint:CGPointMake( 0, label1.frame.origin.y - boundY)];

    [path1 addLineToPoint:CGPointMake(self.frame.size.width - 2 * boundX,label1.frame.origin.y - boundY)];

    CAShapeLayer *dashLayer = [CAShapeLayer layer];

    dashLayer.strokeColor = [UIColor whiteColor].CGColor;

    dashLayer.fillColor = [UIColor clearColor].CGColor;

    // 设置线条宽度

    dashLayer.lineWidth = 1.0;

    //  设置虚线  每间隔十个画一条线,总共十条

    dashLayer.lineDashPattern = @[@10, @10];

    dashLayer.path = path1.CGPath;

    [self.gradient_backgroundView.layer addSublayer:dashLayer];

    }

    }

    渐变背景与虚线

    第三步  描点连线

    由于是懒得在电脑上安装GIF的制作应用,所以就上不了动态图了,简单贴一张完整图片就好

    完整视图

    - (void)drawLine{

    UILabel * label = (UILabel*)[self viewWithTag:1000];//根据横坐标上面的label 获取直线关键点的x 值

    UIBezierPath * path = [[UIBezierPath alloc]init];

    self.path1 = path;

    [path moveToPoint:CGPointMake( label.frame.origin.x - boundX + 7, (600 -arc4random()%600) /600.0 * (self.frame.size.height - boundY*2 )  )];

    //创建折现点标记

    for (NSInteger i = 1; i< 12; i++) {

    UILabel * label1 = (UILabel*)[self viewWithTag:1000 + i];

    CGFloat  arc = arc4random()%600;  //折线点目前给的是随机数

    [path addLineToPoint:CGPointMake(label1.frame.origin.x - boundX,  (600 -arc) /600.0 * (self.frame.size.height - boundY*2 ) )];

    UILabel * falglabel = [[UILabel alloc]initWithFrame:CGRectMake(label1.frame.origin.x , (600 -arc) /600.0 * (self.frame.size.height - boundY*2 )+ boundY  , 30, 15)];

    //  falglabel.backgroundColor = [UIColor blueColor];

    falglabel.tag = 3000+ i;

    falglabel.text = [NSString stringWithFormat:@"%.1f",arc];

    falglabel.font = [UIFont systemFontOfSize:8.0];

    [self addSubview:falglabel];

    }

    [path stroke];

    self.lineChartLayer = [CAShapeLayer layer];

    self.lineChartLayer.path = path.CGPath;

    self.lineChartLayer.strokeColor = [UIColor whiteColor].CGColor;

    self.lineChartLayer.fillColor = [[UIColor clearColor] CGColor];

    self.lineChartLayer.lineWidth = 2;

    self.lineChartLayer.lineCap = kCALineCapRound;

    self.lineChartLayer.lineJoin = kCALineJoinRound;

    [self.gradient_backgroundView.layer addSublayer:self.lineChartLayer];//直接添加导视图上

    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];

    pathAnimation.duration = 3;

    pathAnimation.repeatCount = 1;

    pathAnimation.removedOnCompletion = YES;

    pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];

    pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];

    // 设置动画代理,动画结束时添加一个标签,显示折线终点的信息

    pathAnimation.delegate = self;

    [self.lineChartLayer addAnimation:pathAnimation forKey:@"strokeEnd"];

    }

    虽然这个demo做的是不太美观,不过整体都拆分开了几个方法调用,方便了扩展,后续会为大家继续补充其他功能,还有完整封装好的代码。

    附上Github的链接:

    https://github.com/zengxcgg/LineChartDemo.git 

    相关文章

      网友评论

        本文标题:再简单不过的折线图实现方法

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