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

涉及知识点:

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 

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容