效果图 Demo地址

Demo主要实现了一下几点功能
1.折线图 + stroke动画 + 可左右滚动
2.虚线标注
3.渐变蒙层填充
4.小圆点展示 + 点击放大动画
如果以上效果有满足您当前需要请往下看
拆分界面

调用示例

- (NXLineChartView * )chartView{if (!_chartView) {_chartView = [[NXLineChartView alloc]init];_chartView.backgroundColor = [UIColor whiteColor];_chartView.center = CGPointMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/2);_chartView.bounds = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width-100, 200);_chartView.lineChartXLabelArray = @[@"魅族",@"华为",@"中兴",@"小米",@"苹果",@"一加",@"乐视",@"音乐",@"电视",@"体育"];_chartView.lineChartYLabelArray = @[];_chartView.LineChartDataArray   = @[@100,@40,@60,@45,@100,@55,@33,@120,@40,@100];}return _chartView;
}
#import <UIKit/UIKit.h>@interface NXLineChartView : UIView
@property (nonatomic, strong) NSArray * lineChartYLabelArray;
@property (nonatomic, strong) NSArray * lineChartXLabelArray; // X轴数据
@property (nonatomic, strong) NSArray * LineChartDataArray; // 数据源
@end
1.画折线,这里通过UIBezierPath和CAShapeLayer结合绘图
先创建可左右滚动的scrollView

//可滚动视图
- (UIScrollView *)mainScroll{if (!_mainScroll) {_mainScroll = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];_mainScroll.showsVerticalScrollIndicator = NO;_mainScroll.showsHorizontalScrollIndicator = NO;[self addSubview:_mainScroll];}return _mainScroll;
}
通过LineChartDataArray获得的数据,进行绘制

// 设置折线图
- (void)setLineChartDataArray:(NSArray *)LineChartDataArray{_LineChartDataArray = LineChartDataArray;if (!_LineChartDataArray) return;// [self drawGragient];UIBezierPath * bezierPath = [self getPath];CAShapeLayer * layers = [CAShapeLayer layer];layers.path = bezierPath.CGPath;layers.lineWidth = 2.0;layers.strokeColor = [UIColor redColor].CGColor;layers.fillColor = [UIColor clearColor].CGColor;[self doAnimationWithLayer:layers];[self.mainScroll.layer addSublayer:layers];// self.gredientView.layer.mask = layers;[self addTopPointButton]; // 小圆点[self drawGredientLayer]; // 渐变}- (UIBezierPath *)getPath{self.topPointArray = [[NSMutableArray alloc]init];UIBezierPath * bezierPath = [UIBezierPath bezierPath];for (int idx =0; idx<_LineChartDataArray.count; idx++) {if (idx == 0) {CGPoint startPoint = CGPointMake([_pointXArray[0] floatValue], self.frame.size.height-[_LineChartDataArray[0] floatValue]-bottomMarginScale);[bezierPath moveToPoint:startPoint];[self.topPointArray addObject:[NSValue valueWithCGPoint:startPoint]];}else{CGPoint point = CGPointMake([_pointXArray[idx] floatValue], self.frame.size.height-[_LineChartDataArray[idx] floatValue]-bottomMarginScale);[bezierPath addLineToPoint:point];[self.topPointArray addObject:[NSValue valueWithCGPoint:point]];}}return bezierPath;}
线条动画采用核心动画strokeEnd这个效果实现,代码如下
- (void)doAnimationWithLayer:(CAShapeLayer *)layer{CABasicAnimation * baseAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];baseAnimation.duration = 2;baseAnimation.fromValue = @0.0;baseAnimation.toValue = @1.0;baseAnimation.repeatCount = 1;[layer addAnimation:baseAnimation forKey:@"strokeAnimation"];}
2.虚线标注

- (void)drawRect:(CGRect)rect {CGContextRef ctx = UIGraphicsGetCurrentContext();CGFloat yAxisOffset =  10.f;CGPoint point;CGFloat yStepHeight = rect.size.height / self.LineChartDataArray.count;CGContextSetStrokeColorWithColor(ctx, [UIColor lightGrayColor].CGColor);CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);for (NSUInteger i = 0; i < _LineChartDataArray.count; i++) {point = CGPointMake(10 + yAxisOffset, (rect.size.height - i * yStepHeight + 10 / 2));CGContextMoveToPoint(ctx, point.x, point.y);// add dotted style gridCGFloat dash[] = {6, 5};// dot diameter is 20 pointsCGContextSetLineWidth(ctx, 0.5);CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);CGContextSetLineCap(ctx, kCGLineCapRound);CGContextSetLineDash(ctx, 0.0, dash, 2);// 这里是改变虚线的宽度CGRect frame = CGRectMake(rect.origin.x, rect.origin.y, self.totalWidth, rect.size.height);CGContextAddLineToPoint(ctx, CGRectGetWidth(frame) - 5 + 5, point.y);CGContextStrokePath(ctx);}}
3.渐变蒙层填充

/*@parameter 背景颜色填充*/- (void)drawGredientLayer{CAGradientLayer *gradientLayer = [CAGradientLayer layer];gradientLayer.frame = CGRectMake(0, 0, self.totalWidth, self.frame.size.height-bottomMarginScale);gradientLayer.colors = @[(__bridge id)[UIColor colorWithRed:250/255.0 green:170/255.0 blue:10/255.0 alpha:0.8].CGColor,(__bridge id)[UIColor colorWithWhite:1 alpha:0.4].CGColor];gradientLayer.locations=@[@0.0,@1.0];gradientLayer.startPoint = CGPointMake(0.0,0.0);gradientLayer.endPoint = CGPointMake(1,0);UIBezierPath *gradientPath = [UIBezierPath bezierPath];[gradientPath moveToPoint:CGPointMake([_pointXArray[0] floatValue], self.frame.size.height-bottomMarginScale)];for (int i=0; i<_LineChartDataArray.count; i++) {[gradientPath addLineToPoint:CGPointMake([_pointXArray[i] floatValue], self.frame.size.height-[_LineChartDataArray[i] floatValue]-bottomMarginScale)];}[gradientPath addLineToPoint:CGPointMake([_pointXArray[_pointXArray.count-1] floatValue], self.frame.size.height-bottomMarginScale)];CAShapeLayer *arc = [CAShapeLayer layer];arc.path = gradientPath.CGPath;gradientLayer.mask = arc;[self.mainScroll.layer addSublayer:gradientLayer];}
4.小圆点展示 + 点击放大动画
小圆点

// 添加小圆点
- (void)addTopPointButton{if (self.topPointArray.count ==0) return;for (int idx =0; idx<self.topPointArray.count; idx++) {CGPoint point = [self.topPointArray[idx] CGPointValue];UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];button.center = point;button.bounds = CGRectMake(0, 0, 10, 10);button.layer.cornerRadius = 5;button.clipsToBounds = YES;button.backgroundColor = [UIColor cyanColor];button.tag = GAP+idx;[button setTitle:[self.LineChartDataArray[idx] stringValue] forState:UIControlStateNormal];[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];button.titleLabel.font = [UIFont systemFontOfSize:5];button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);[button addTarget:self action:@selector(didSelectButtonClick:) forControlEvents:UIControlEventTouchUpInside];[self.mainScroll addSubview:button];}}
小圆点点击放大动画采用核心动画scale

- (void)didSelectButtonClick:(UIButton *)sender{for (id emptyObj in self.mainScroll.subviews) {if ([emptyObj isKindOfClass:[UIButton class]]) {UIButton * btn = (UIButton *)emptyObj;//  btn.bounds = CGRectMake(0, 0, 5, 5);//  [btn setTitleColor:[UIColor clearColor] forState:UIControlStateNormal];[btn.layer removeAllAnimations];}}[self doScaleAnimationWithView:sender];NSLog(@"%@",[self.LineChartDataArray[sender.tag-GAP] stringValue]);[sender setTitle:[self.LineChartDataArray[sender.tag-GAP] stringValue] forState:UIControlStateNormal];[sender setTitleColor:[UIColor redColor] forState:UIControlStateNormal];sender.titleLabel.font = [UIFont systemFontOfSize:5];}- (void)doScaleAnimationWithView:(UIView *)view{CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];animation.duration = 0.3;animation.values = @[@2,@1.5,@0.8,@1,@2];animation.repeatCount = 2;animation.fillMode = kCAFillModeForwards;animation.removedOnCompletion = NO;[view.layer addAnimation:animation forKey:@"scaleAnimations"];
}
底部X坐标轴数据填充

// 底部X视图
- (void)setLineChartXLabelArray:(NSArray *)lineChartXLabelArray{_lineChartXLabelArray = lineChartXLabelArray;if (!_lineChartXLabelArray) return;_pointXArray = [[NSMutableArray alloc]init];// CGFloat labelWidthScale = (self.frame.size.width-leftXMarginScale-rightXMarginScale)/_lineChartXLabelArray.count;self.totalWidth =0;for (int idx = 0; idx < _lineChartXLabelArray.count; idx ++) {CGFloat labelWidthScale = [self getLabelWidthWithText:_lineChartXLabelArray[idx]];CGFloat x = self.totalWidth+marginScale;CGFloat y = self.frame.size.height- lineChartXlabelHeight;UILabel * label = [[UILabel alloc]init];label.frame = CGRectMake(x, y, labelWidthScale, lineChartXlabelHeight);label.text = _lineChartXLabelArray[idx];label.textAlignment = NSTextAlignmentCenter;label.textColor = [UIColor redColor];label.font = [UIFont systemFontOfSize:fontSize];[_pointXArray addObject:[NSString stringWithFormat:@"%.f",label.center.x]];[self.mainScroll addSubview:label];self.totalWidth = label.frame.origin.x+label.frame.size.width;[self.mainScroll setContentSize:CGSizeMake(CGRectGetMaxX(label.frame), 0)];}}
再看下调用示例比较简单
- (NXLineChartView * )chartView{if (!_chartView) {_chartView = [[NXLineChartView alloc]init];_chartView.backgroundColor = [UIColor whiteColor];_chartView.center = CGPointMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/2);_chartView.bounds = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width-100, 200);_chartView.lineChartXLabelArray = @[@"魅族",@"华为",@"中兴",@"小米",@"苹果",@"一加",@"乐视",@"音乐",@"电视",@"体育"];_chartView.lineChartYLabelArray = @[];_chartView.LineChartDataArray   = @[@100,@40,@60,@45,@100,@55,@33,@120,@40,@100];}return _chartView;
}

Demo地址

iOS 折线图实现,虚线,渐变色填充,线条动画相关推荐

  1. iOS 折线图、柱状图的简单实现

    首先我得感谢某位博主,非常抱歉,因为之前直接下载博主提供这篇文章的demo,然后去研究了,没记住博主的名字.再次非常感谢. 而这个dome我又修改了一些,完善了一些不美观的bug,当然还有,后面会陆续 ...

  2. ios 折线图_《解神者》ios和安卓互通吗 ios和安卓互通分析

    导读 解神者ios和安卓数据互通是玩家们想知道事情,如果互通两种机型的玩家能一起进行游戏喔,那么解神者ios和安卓互通吗.解神者苹果和安卓能一起玩吗呢,九游手游网为大家带来介绍. *解神者ios和安卓 ...

  3. python可视化(2-2)绘图对象(折线图、散点图、面积图、填充图)

    本文主要介绍折线图.散点图.面积图和填充图 plt.plot是matplotlib最基础的接口,matplotlib作者也将这个接口设计得足够简单,以至于只需要输入一个参数(数组,列表型数据),就能够 ...

  4. D3.js之折线图动画

    主要实现的效果一个折线图,然后线条可以从头到尾的出现. 折线图的代码基本上是别人的(本人也是正在学习的),自己只是在这上面基础上添加动画和一些文字和circle 参考:参考折线图的博客 参考SVG动画 ...

  5. matplotlib数据可视化实战——折线图+散点图

    今天通过几个实践样例学习了使用matplotlib绘制图像. 过程中出现了很多问题,但是都通过查阅资料一一解决了.最后看到绘制好的图像弹出来以后,内心还是有点小激动. 字体调用问题: 1.导入数据库 ...

  6. matlab绘制折线图基本操作

    本篇博客主要总结matlab绘制折线图的基本操作,使用的函数是plot函数,关于plot的函数语法规则,这里不再赘述,可以参考matlab官方文档,https://ww2.mathworks.cn/h ...

  7. Echarts折线图区域填充问题解决

    前言 我们用Echarts做折线图时,有时我们需要在两条折线图之间有颜色填充效果,如果折线的数值范围涉及到负数,颜色只会填充到Y轴0刻度之上,而且上折线不能有负数,效果如下图: 我的调整思路: 将两条 ...

  8. 【Web动画】SVG 实现复杂线条动画

    在上一篇文章中,我们初步实现了一些利用基本图形就能完成的线条动画: [Web动画]SVG 线条动画入门 当然,事物都是朝着熵增焓减的方向发展的,复杂线条也肯定比有序线条要多. 很多时候,我们无法人工去 ...

  9. echarts柱状图、折线图 渐变色,填充渐变色,鼠标移入样式,双y轴

    基础代码都一样,根据配置的seriesDta的type不同,展现出的效果不同,每一个echarts都对应单独的series 版本不同可能实现效果不同,具体查看官网哦. 安装: npm install ...

最新文章

  1. 用计算机计算教学反思,《用计算器计算》教学反思
  2. Git 使用规范流程
  3. [密码学] DES(二)
  4. 【存储知识学习】第五章-5.1-5.3 RAID磁盘阵列-《大话存储》 阅读笔记
  5. ES6之Module 的加载实现(3)
  6. python静态方法可以被继承吗_python 类的继承 实例方法.静态方法.类方法的代码解析...
  7. 云存储精华问答 | 如何选择云迁移策略?
  8. 数据可视化:常用图表使用总结
  9. 《Android游戏开发详解》一3.5 继承
  10. labview混合编程学习
  11. java架构师之路-并发编程
  12. 【Docker】Docker下载与安装
  13. dsm php virtualbox,当蜗牛遇上群晖 - VirtualBox下群晖系统安装详解
  14. Scala zio-actors与akka-actor集成
  15. Mysql磁盘碎片整理教程
  16. IntelliJ IDEA 在使用manven后的纠结(每次修改代码都要重启tomcat才能看效果吗?),请各位大侠来看看问题
  17. 令克软件再推OpenAPI与MAS系统服务,强大引擎赋能券商多元化发展
  18. 骨感传导蓝牙耳机怎么样、骨感传导蓝牙耳机有什么特点
  19. redis中以层级关系、目录形式存储数据
  20. 奥维奥:新零售真的只有资本才玩的起吗?

热门文章

  1. Sage X3基础资料
  2. 预警短信python_zabbix 利用python脚本实现短信告警
  3. ViewBag 和 ViewData 的用法和区别
  4. charles抓包工具详细教程
  5. element ui 样式穿透
  6. form is not define的原因-JavaScript
  7. android压感补充
  8. vscode——html+css+js+(jQuery)动态登陆界面
  9. 职场“年轻崇拜”?45岁程序员精通各种技术体系,却连个面试机会都没有
  10. 连续三年缩招,北交电信竞争愈演愈烈