iOS 折线图实现
图表绘制的过程实际上是坐标位置的计算过程,至于画线只要有了position,通过CAShapeLayer+BezierPath很快就可以画出来,这里提供一个绘制折线的demo,贵在思路,有需要的可以参考
demo下载地址:https://github.com/qqcc1388/TYLineViewDemo
话不多说,效果图和代码
//单根折线实现
#import <UIKit/UIKit.h>
@interface TYLineView : UIView
@property (nonatomic,strong) NSArray *datas;
@property (nonatomic,strong) UIColor *lineColor;
/**
是否显示灰色背景
*/
@property (nonatomic,assign) BOOL isShowBack;
@end
#import "TYLineView.h"
#define kMarginX 30
#define kMarginY 20
@interface TYLineView ()
@property (nonatomic,strong)CAShapeLayer *shapeLayer;//划线layer
@property (nonatomic,strong) CAShapeLayer *backLayer; //背景
@property (nonatomic,assign)CGFloat maxYvalue; //最大y值
@property (nonatomic,assign) NSInteger xAxisCount; //x轴点数
@property (nonatomic,assign) NSInteger yAxisCount; //y轴点数
@end
@implementation TYLineView
-(instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
-(void)initialize
{
//闭合背景
_backLayer = [[CAShapeLayer alloc] init];
_backLayer.fillColor = [UIColor grayColor].CGColor;
_backLayer.frame = self.bounds;
[self.layer addSublayer:_backLayer];
//主线段
_shapeLayer = [[CAShapeLayer alloc] init];
_shapeLayer.lineWidth = 1;
_shapeLayer.lineCap = @"round";
_shapeLayer.lineJoin = @"round";
_shapeLayer.strokeColor = [UIColor redColor].CGColor;
_shapeLayer.fillColor = [UIColor clearColor].CGColor;
_shapeLayer.frame = self.bounds;
[self.layer addSublayer:_shapeLayer];
//初始化
self.isShowBack = NO;
self.yAxisCount = 5;
self.backgroundColor = [UIColor cyanColor];
}
-(void)setDatas:(NSArray *)datas{
//保存数据
_datas = datas;
//设置最大值
self.maxYvalue = 200;
//设置xAxisCount
self.xAxisCount = datas.count;
[self setNeedsDisplay];
//划线
[self drawLine];
}
-(void)drawLine
{
CGFloat totalHeight = CGRectGetHeight(self.frame) - kMarginY*2;
// CGFloat maxY = self.maxYvalue;
CGFloat totoalWidth = CGRectGetWidth(self.frame) - kMarginX*2;
//x轴每一段的宽度
CGFloat perX = totoalWidth/(self.xAxisCount-1)*1.0;
CGFloat yper = totalHeight/self.maxYvalue; //y轴一个单位的高度
//主线段曲线
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
//背景曲线
UIBezierPath *backPath = [UIBezierPath bezierPath];
//原点
CGPoint startPoint = CGPointMake(kMarginX,totalHeight + kMarginY);
[backPath moveToPoint:startPoint];
for (int i = 0; i < _datas.count; i++) {
NSInteger valueY = [_datas[i] integerValue];
CGFloat x = kMarginX + perX*i;
CGFloat y = (totalHeight + kMarginY) - yper*valueY;
CGPoint point = CGPointMake(x,y);
if (i == 0) {
[bezierPath moveToPoint:point];
}else{
[bezierPath addLineToPoint:point];
}
[backPath addLineToPoint:point];
}
//终点
CGPoint endPoint = CGPointMake(kMarginX + perX*(self.datas.count-1), totalHeight + kMarginY);
[backPath addLineToPoint:endPoint];
//开始动画
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = 2.0f;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.fromValue = @(0);
animation.toValue =@(1);
self.shapeLayer.path = bezierPath.CGPath;
[self.shapeLayer addAnimation:animation forKey:@"strokeEnd"];
self.backLayer.path = backPath.CGPath;
}
-(void)drawRect:(CGRect)rect
{
[super drawRect:rect];
UIBezierPath *path = [UIBezierPath bezierPath];
[path setLineWidth:1.0f];
[[UIColor redColor] set];
CGFloat totalWidth = self.bounds.size.width;
CGFloat totalHeight = self.bounds.size.height;
//画坐标系
//------> y轴
[path moveToPoint:CGPointMake(kMarginX,kMarginY)];
[path addLineToPoint:CGPointMake(kMarginX, totalHeight - kMarginY)];
//------> x轴
[path addLineToPoint:CGPointMake(totalWidth - kMarginX, totalHeight - kMarginY)];
[path stroke];
//线段 - y轴
CGFloat perHeight = ((totalHeight - kMarginY*2)/(self.yAxisCount));
for (int i = 0; i < self.yAxisCount; i++) {
CGFloat y = perHeight*i + kMarginY;
UIBezierPath *path = [UIBezierPath bezierPath];
[path setLineWidth:1.0f];
[[UIColor blueColor] set];
[path moveToPoint:CGPointMake(kMarginX, y)];
[path addLineToPoint:CGPointMake(kMarginX+ 5, y)];
[path stroke];
}
//线段 - x轴
CGFloat perWidth = (totalWidth - kMarginX*2)/(self.xAxisCount*1.0);
for (int i = 0; i < self.xAxisCount; i++) {
CGFloat x = perWidth*(i+1);
CGFloat y = totalHeight - kMarginY;
UIBezierPath *path = [UIBezierPath bezierPath];
[path setLineWidth:1.0f];
[[UIColor blueColor] set];
[path moveToPoint:CGPointMake(x+kMarginX, y)];
[path addLineToPoint:CGPointMake(x+kMarginX, y-5)];
[path stroke];
}
//画y轴文字
NSMutableArray *yArr = [NSMutableArray array];
for (int i = 0; i < self.yAxisCount; i++) {
[yArr addObject:[NSString stringWithFormat:@"%.f",self.maxYvalue - self.maxYvalue/self.yAxisCount *i]];
}
[yArr addObject:@"0"];
for (int i = 0; i < yArr.count ; i++) {
NSString *title = yArr[i];
CGFloat y = ((totalHeight - kMarginY*2)/(self.yAxisCount))*i + kMarginY;
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setAlignment:NSTextAlignmentCenter];
[title drawInRect:CGRectMake(0,y-5, kMarginX, 20) withAttributes:@{NSForegroundColorAttributeName:[UIColor redColor],NSFontAttributeName:[UIFont systemFontOfSize:10],NSParagraphStyleAttributeName:style}];
}
}
#pragma mark setter getter
-(void)setLineColor:(UIColor *)lineColor{
_lineColor = lineColor;
self.shapeLayer.strokeColor = lineColor.CGColor;
}
-(void)setIsShowBack:(BOOL)isShowBack{
_isShowBack = isShowBack;
self.backLayer.hidden = !isShowBack;
}
多根线一起
#import <UIKit/UIKit.h>
@interface TYMultiLineView : UIView
-(void)addLineWithDatas:(NSArray *)datas lineColor:(UIColor *)color animated:(BOOL)animated;
@end
#import "TYMultiLineView.h"
#define kMarginX 30
#define kMarginY 20
@interface TYMultiLineView ()
@property (nonatomic,assign)CGFloat maxYvalue; //最大y值
@property (nonatomic,assign) NSInteger xAxisCount; //x轴点数
@property (nonatomic,assign) NSInteger yAxisCount; //y轴点数
@end
@implementation TYMultiLineView
-(instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
-(void)initialize
{
self.backgroundColor = [UIColor cyanColor];
self.maxYvalue = 200;
self.yAxisCount = 5;
self.xAxisCount = 5;
[self setNeedsDisplay];
}
-(void)addLineWithDatas:(NSArray *)datas lineColor:(UIColor *)color animated:(BOOL)animated{
//设置最大值
self.maxYvalue = 200;
//设置xAxisCount
self.xAxisCount = datas.count;
CAShapeLayer* lineLayer = [[CAShapeLayer alloc] init];
lineLayer.lineWidth = 1;
lineLayer.lineCap = @"round";
lineLayer.lineJoin = @"round";
lineLayer.strokeColor = color.CGColor;
lineLayer.fillColor = [UIColor clearColor].CGColor;
lineLayer.frame = self.bounds;
[self.layer addSublayer:lineLayer];
UIBezierPath *path = [self prepareBezierPathDatas:datas];
lineLayer.path = path.CGPath;
if(animated){
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = 2.0f;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.fromValue = @(0);
animation.toValue =@(1);
[lineLayer addAnimation:animation forKey:@"strokeEnd"];
}
}
-(UIBezierPath *)prepareBezierPathDatas:(NSArray *)datas
{
CGFloat totalHeight = CGRectGetHeight(self.frame) - kMarginY*2;
// CGFloat maxY = self.maxYvalue;
CGFloat totoalWidth = CGRectGetWidth(self.frame) - kMarginX*2;
//x轴每一段的宽度
CGFloat perX = totoalWidth/(self.xAxisCount-1)*1.0;
CGFloat yper = totalHeight/self.maxYvalue; //y轴一个单位的高度
//主线段曲线
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
for (int i = 0; i < datas.count; i++) {
NSInteger valueY = [datas[i] integerValue];
CGFloat x = kMarginX + perX*i;
CGFloat y = (totalHeight + kMarginY) - yper*valueY;
CGPoint point = CGPointMake(x,y);
if (i == 0) {
[bezierPath moveToPoint:point];
}else{
[bezierPath addLineToPoint:point];
}
}
return bezierPath;
}
-(void)drawRect:(CGRect)rect
{
[super drawRect:rect];
UIBezierPath *path = [UIBezierPath bezierPath];
[path setLineWidth:1.0f];
[[UIColor redColor] set];
CGFloat totalWidth = self.bounds.size.width;
CGFloat totalHeight = self.bounds.size.height;
//画坐标系
//------> y轴
[path moveToPoint:CGPointMake(kMarginX,kMarginY)];
[path addLineToPoint:CGPointMake(kMarginX, totalHeight - kMarginY)];
//------> x轴
[path addLineToPoint:CGPointMake(totalWidth - kMarginX, totalHeight - kMarginY)];
[path stroke];
//线段 - y轴
CGFloat perHeight = ((totalHeight - kMarginY*2)/(self.yAxisCount));
for (int i = 0; i < self.yAxisCount; i++) {
CGFloat y = perHeight*i + kMarginY;
UIBezierPath *path = [UIBezierPath bezierPath];
[path setLineWidth:1.0f];
[[UIColor blueColor] set];
[path moveToPoint:CGPointMake(kMarginX, y)];
[path addLineToPoint:CGPointMake(kMarginX+ 5, y)];
[path stroke];
}
//线段 - x轴
CGFloat perWidth = (totalWidth - kMarginX*2)/(self.xAxisCount*1.0);
for (int i = 0; i < self.xAxisCount; i++) {
CGFloat x = perWidth*(i+1);
CGFloat y = totalHeight - kMarginY;
UIBezierPath *path = [UIBezierPath bezierPath];
[path setLineWidth:1.0f];
[[UIColor blueColor] set];
[path moveToPoint:CGPointMake(x+kMarginX, y)];
[path addLineToPoint:CGPointMake(x+kMarginX, y-5)];
[path stroke];
}
//画y轴文字
NSMutableArray *yArr = [NSMutableArray array];
for (int i = 0; i < self.yAxisCount; i++) {
[yArr addObject:[NSString stringWithFormat:@"%.f",self.maxYvalue - self.maxYvalue/self.yAxisCount *i]];
}
[yArr addObject:@"0"];
for (int i = 0; i < yArr.count ; i++) {
NSString *title = yArr[i];
CGFloat y = ((totalHeight - kMarginY*2)/(self.yAxisCount))*i + kMarginY;
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setAlignment:NSTextAlignmentCenter];
[title drawInRect:CGRectMake(0,y-5, kMarginX, 20) withAttributes:@{NSForegroundColorAttributeName:[UIColor redColor],NSFontAttributeName:[UIFont systemFontOfSize:10],NSParagraphStyleAttributeName:style}];
}
}
使用方法
lineView:
[self.lineView setDatas:[self prepareDatas]];
multiLineView:
[self.multiLineView addLineWithDatas:[self prepareDatas] lineColor:[UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1] animated:YES];
-(NSArray *)prepareDatas{
NSMutableArray *datas = [NSMutableArray array];
for (int i = 0; i < 5; i++) {
[datas addObject:@(arc4random_uniform(201)).stringValue];
}
return datas;
}
关于动画画线方法:给shapelayer添加strokeEnd动画
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = 2.0f;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.fromValue = @(0);
animation.toValue =@(1);
[lineLayer addAnimation:animation forKey:@"strokeEnd"];
demo中还有很多地方需要完善,这里仅仅是抛砖引玉提供一种实现的方案,细节的处理和其他的特殊需求请参考demo,自己进行拓展
iOS 折线图实现的更多相关文章
- iOS 折线图、柱状图的简单实现
首先我得感谢某位博主,非常抱歉,因为之前直接下载博主提供这篇文章的demo,然后去研究了,没记住博主的名字.再次非常感谢. 而这个dome我又修改了一些,完善了一些不美观的bug,当然还有,后面会陆续 ...
- IOS折线图二
上周把项目的折线图给做了下,今天想着把它完善完善,自己设置了不同的数据源来测试,哈哈,还真遇到问题了, 就是给图表设置折点数为0时,视图显示的还是原来的,由于数据为空,应该将其设置为空,所以想着怎么把 ...
- IOS折线图
做项目要统计商品的销售情况,美工那边给了效果图,自己就按照效果图自定义了一个ScrollView.整体效果不错,在做的过程中遇到的问题也记录一下. 现在这个还有许多优化的地方: 1.一个表中只能画一个 ...
- iOS绘制坐标图,折线图-Swift
坐标图,经常会在各种各样的App中使用,最常用的一种坐标图就是折线图,根据给定的点绘制出对应的坐标图是最基本的需求.由于本人的项目需要使用折线图,第一反应就是搜索已经存在的解决方案,因为这种需求应该很 ...
- iOS 动画绘制线条颜色渐变的折线图
效果图 .................... 概述 现状 折线图的应用比较广泛,为了增强用户体验,很多应用中都嵌入了折线图.折线图可以更加直观的表示数据的变化.网络上有很多绘制折线图的demo,有 ...
- IOS绘制渐变背景色折线图的一种尝试
1.绘制折线图 上次在群里看到一个折线图划的很漂亮,自己想实现一个这样的 ,但是一直没什么头绪,不知道怎么做,就开始在网上查找划线,绘 制渐变色这一块的内容,用最笨的方式,自己尝试的写了一些,也没 有 ...
- UUChart的使用--iOS绘制折线图
UUChart是一个用于绘制图表的第三方,尤其适合去绘制折线图. 二.下载地址: https://github.com/ZhipingYang/UUChartView 三.使用 第一步.首先我们将下载 ...
- IOS使用Core-Plot画折线图
关于Core-Plot的配置.大家能够參考我的上一篇博客:http://1.wildcat.sinaapp.com/?p=99 版权全部.转载请注明原文转自:http://blog.csdn.net/ ...
- iOS:使用贝塞尔曲线绘制图表(折线图、柱状图、饼状图)
1.介绍: UIBezierPath :画贝塞尔曲线的path类 UIBezierPath定义 : 贝赛尔曲线的每一个顶点都有两个控制点,用于控制在该顶点两侧的曲线的弧度. 曲线的定义有四个点:起始点 ...
随机推荐
- tomcat启动不了,内存溢出
今天下午不知道做了什么,然后tomcat启动了10分钟还启动不了.然后看控制台报错信息,说是内存溢出.然后就各种百度,终于解决了.在这里记录提示自己,避免这种问题再次出现还要浪费时间去找方法解决. 最 ...
- seajs源码阅读
乘着周日有点时间,阅读一下玉伯大神的源码. seajs的源码写得真的很好,很是佩服,工整美观不愧是大神,造福百姓. 说起seajs不得不说,AMD和CMD的区别. CMD 推崇依赖就近,AMD 推崇 ...
- Jenkins 配置邮件通知
jenkins 是一个开源的自动化服务器.通过Jenkins,可以通过自动化加速软件开发过程.Jenkins管理和控制各种开发的生命周期过程,包括构建,文档,测试,包,阶段,部署,静态分析等等.您可以 ...
- MySQL自动化(全量+增量)备份脚本
文章转自:http://www.it-hack.cn/forum.php?mod=viewthread&tid=220&extra=page%3D1 一.MySQL的日常备份方案: 全 ...
- Javasript 正则匹配任意字符
今天在写Js匹配任意字符的时候发现使用.不好使,当输入内容有回车的时候就会失效. 后来上网查,发现js的任意字符不包括\n. 本来想写一个trim后长度为10的正则验证,最后使用[\s|\S]来代替任 ...
- 随记之 -- diy相册
最近一段时间楼下在整修房子,一到早晨6点多的时候,电钻声.敲打声齐鸣,实在是不能好好的睡个安稳觉 (┳_┳)... 这周六像往常一样,以为又要被惊醒了,所以早早的就醒了,谁知竟然出奇的安静,难道施工队 ...
- IE浏览器兼容问题(上)——html和css的兼容写法
用户使用的浏览器五花八门,我们要保证每一种浏览器都能兼容我们的代码,不能要求用户去改变浏览器,那么就得在我们的代码上下功夫.此时我们要用到hack. HACK就是针对不同的浏览器写不同的HTML.CS ...
- JVM学习(1)——通过实例总结Java虚拟机的运行机制-转载http://www.cnblogs.com/kubixuesheng/p/5199200.html
JVM系类的文章全部转载自:http://www.cnblogs.com/kubixuesheng/p/5199200.html 特别在此声明.那位博主写的真的很好 ,感谢!! 俗话说,自己写的代码, ...
- 禁用Ubuntu 15.04登录界面显示客人会话
在控制台打开如下配置文件,如果没有就自己创建一个: sudo vi /etc/lightdm/lightdm.conf 向文件中添加如下内容: [SeatDefaults] greeter-sessi ...
- 流畅python学习笔记:第十一章:抽象基类
__getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...