IOS折线图
做项目要统计商品的销售情况,美工那边给了效果图,自己就按照效果图自定义了一个ScrollView。整体效果不错,在做的过程中遇到的问题也记录一下。

现在这个还有许多优化的地方:
1.一个表中只能画一个折线
2.目前的要求最小值为0,没考虑负数的最小值
//
// LineChartView.h
// chart
//
// Created by City--Online on 15/9/17.
// Copyright © 2015年 City--Online. All rights reserved.
//
#import <UIKit/UIKit.h>
//设置两点的水平间距
#define SPACING 70.0
//文本类型
typedef NS_ENUM(NSInteger, TitleType) {
TitleForX,
TitleForPoint
};
@class LineChartView;
@protocol LineChartDataSource <NSObject>
@required
//折点数量
-(NSInteger)numberForChart:(LineChartView *)chart;
//折点数值
-(float)chart:(LineChartView *)chart valueAtIndex:(NSInteger)index;
@optional
//X轴坐标是否有背景色
-(BOOL)chart:(LineChartView *)chart backGroundColorAtXPointIndex:(NSInteger)index;
//X 轴的标题
-(NSString *)chart:(LineChartView *)chart titleForXLabelAtIndex:(NSInteger)index;
@end
@interface LineChartView : UIScrollView
@property(nonatomic,assign)id<LineChartDataSource> dataSource;
@end
//
// LineChartView.m
// chart
//
// Created by City--Online on 15/9/17.
// Copyright © 2015年 City--Online. All rights reserved.
//
#import "YZPLineChartView.h"
@interface YZPLineChartView ()
@property (nonatomic,strong) CAShapeLayer * linePath;
@property(nonatomic,assign)NSInteger maxValue; //最大值
@property(nonatomic,assign)NSInteger count; //点数
@property(nonatomic,assign)CGFloat avgHeight; //刻度
@end
@implementation YZPLineChartView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor=[UIColor whiteColor];
_linePath=[CAShapeLayer layer];
_linePath.lineCap=kCALineCapRound;
_linePath.lineJoin=kCALineJoinBevel;
_linePath.lineWidth=;
_linePath.fillColor=[UIColor clearColor].CGColor;
self.bounces=NO;
self.showsHorizontalScrollIndicator=NO;
self.showsVerticalScrollIndicator=NO;
_maxValue=;
}
return self;
}
//最大值
-(NSInteger)maxValue
{
; i<self.count; i++) {
NSInteger value=[_dataSource chart:self valueAtIndex:i];
_maxValue=value>_maxValue?value:_maxValue;
}
return _maxValue;
}
//点数
-(NSInteger)count
{
return [_dataSource numberForChart:self];
}
//刻度
-(CGFloat)avgHeight
{
CGFloat height=self.frame.size.height;
_avgHeight=(height--)/self.maxValue;
return _avgHeight;
}
-(void)drawRect:(CGRect)rect
{
[super drawRect:rect];
//每次加载先删除原有图层
int count = [self.layer.sublayers count];
; i<count; i++) {
[self.layer.sublayers[] removeFromSuperlayer];
}
//不能通过for in 删除 was mutated while being enumerated 遍历的时候不能删除
// for (CALayer *layer in self.layer.sublayers) {
// [layer removeFromSuperlayer];
// }
) {
return;
}
[self.layer addSublayer:_linePath];
self.contentSize=CGSizeMake((self.count)*SPACING, self.bounds.size.height);
//画底部边线
[self drawVerticalLineStartPoint:CGPointMake(, self.bounds.size.height-) withEndPoint:CGPointMake(self.contentSize.width, self.bounds.size.height-) withColor:[UIColor grayColor] ];
//画折线
[self drawBrokenLine];
}
//画底部边线
-(void)drawBottomLine
{
UIBezierPath *bottomLine=[UIBezierPath bezierPath];
[bottomLine moveToPoint:CGPointMake(, self.bounds.size.height-)];
[bottomLine addLineToPoint:CGPointMake(self.contentSize.width, self.bounds.size.height-)];
[[UIColor colorWithRed:0.902f green:0.902f blue:0.902f alpha:1.00f] setStroke];
[bottomLine stroke];
}
//画竖线
-(void)drawVerticalLineStartPoint:(CGPoint) startPoint withEndPoint:(CGPoint) endPoint withColor:(UIColor *)color
{
CAShapeLayer *layer=[CAShapeLayer layer];
layer.lineCap=kCALineCapRound;
layer.lineJoin=kCALineJoinBevel;
layer.lineWidth=0.5;
layer.fillColor=[UIColor clearColor].CGColor;
[self.layer addSublayer:layer];
UIBezierPath *bottomLinePath=[UIBezierPath bezierPath];
[bottomLinePath moveToPoint:startPoint];
[bottomLinePath addLineToPoint:endPoint];
layer.path=bottomLinePath.CGPath;
layer.strokeColor=[UIColor colorWithRed:0.902f green:0.902f blue:0.902f alpha:1.00f].CGColor;
}
//画点
-(void)drawPointWithCenterPoint:(CGPoint)point radius:(float)radius strokeColor:(UIColor *)strokeColor fillColor:(UIColor *)fillColor
{
UIBezierPath *drawPoint=[UIBezierPath bezierPath];
[drawPoint addArcWithCenter:point radius:radius startAngle:M_PI* endAngle:M_PI* clockwise:YES];
CAShapeLayer *layer=[[CAShapeLayer alloc]init];
layer.path=drawPoint.CGPath;
layer.strokeColor=strokeColor.CGColor;
layer.fillColor=fillColor.CGColor;
[self.layer addSublayer:layer];
}
// 画文字 原本使用[NSstring drawAtPoint: withAttributes:]方法 但是画之后并不随着ScrollView滚动 所以用Label
-(void)drawText:(NSString *)text withPoint:(CGPoint)point withType:(TitleType) type withIndex:(NSInteger)index
{
CGRect frame=[text boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:.f]} context:nil];
UILabel *label=[[UILabel alloc]init];
CGPoint pointForValueString=CGPointMake(point.x-, point.y);
) {
pointForValueString.y=point.y-frame.size.height-;
}
)
{
pointForValueString.y=point.y+frame.size.height-;
}
label.frame=CGRectMake(pointForValueString.x, pointForValueString.y, , );
label.textAlignment=NSTextAlignmentCenter;
if (type==TitleForPoint) {
label.textColor=[UIColor redColor];
label.font=[UIFont systemFontOfSize:.f];
}
else if (type==TitleForX)
{
label.frame=CGRectMake(pointForValueString.x, pointForValueString.y+, ,);
if (_dataSource&&[_dataSource respondsToSelector:@selector(chart:backGroundColorAtXPointIndex:)]) {
if ([_dataSource chart:self backGroundColorAtXPointIndex:index]) {
label.backgroundColor=[UIColor redColor];
label.textColor=[UIColor whiteColor];
label.layer.cornerRadius=label.bounds.size.width/;
label.clipsToBounds=YES;
}
else
{
label.backgroundColor=[UIColor whiteColor];
label.textColor=[UIColor colorWithRed:0.298f green:0.298f blue:0.298f alpha:1.00f];
}
}
else
{
label.textColor=[UIColor colorWithRed:0.298f green:0.298f blue:0.298f alpha:1.00f];
}
label.font=[UIFont systemFontOfSize:.f];
}
label.text=text;
[self addSubview:label];
}
-(void)drawBrokenLine
{
UIBezierPath *path=[UIBezierPath bezierPath];
; i<self.count; i++) {
CGFloat value=[_dataSource chart:self valueAtIndex:i];
CGPoint point=[self pointWithValue:value index:i];
//画竖线
[self drawVerticalLineStartPoint:CGPointMake((i+) withEndPoint:point withColor:
[UIColor blueColor]];
//画折点
[self drawPointWithCenterPoint:point radius: strokeColor:[UIColor redColor] fillColor:self.backgroundColor];
//画X轴刻度点
UIColor *pointColor=[UIColor colorWithRed:0.902f green:0.902f blue:0.902f alpha:1.00f];
[self drawPointWithCenterPoint:CGPointMake((i+) radius: strokeColor:pointColor fillColor:pointColor];
//画文字
NSString *valueString=[NSString stringWithFormat:@"%ld",(long)value];
[self drawText:valueString withPoint:point withType:TitleForPoint withIndex:i];
//画X轴
if (_dataSource&&[_dataSource respondsToSelector:@selector(chart:titleForXLabelAtIndex:)]) {
NSString *xstring=[_dataSource chart:self titleForXLabelAtIndex:i];
[self drawText:xstring withPoint:CGPointMake(point.x, self.bounds.size.height-) withType:TitleForX withIndex:i];
}
//画折线
//贝塞尔曲线
) {
[path moveToPoint:point];
}else{
[path addLineToPoint:point];
}
}
path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle=kCGLineJoinRound;
path.lineWidth=0.5;
[[UIColor redColor]setStroke];
CABasicAnimation *pathAnimation=[CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation.duration = ;
pathAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pathAnimation.fromValue=[NSNumber numberWithFloat:0.0f];
pathAnimation.toValue=[NSNumber numberWithFloat:1.0f];
pathAnimation.autoreverses=NO;
_linePath.path=path.CGPath;
_linePath.strokeColor=[UIColor redColor].CGColor;
[_linePath addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
_linePath.strokeEnd = 1.0;
}
//根据索引计算出折点的位置
-(CGPoint)pointWithValue:(NSInteger)value index:(NSInteger)index
{
CGFloat height=self.frame.size.height;
);
}
@end
调用:
#import "ViewController.h"
#import "LineChartView.h"
@interface ViewController ()<LineChartDataSource>
@property (nonatomic,strong) NSArray *points;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_points=@[@,@,@,@,@,@,@,@,@,@];
LineChartView *lineChart=[[LineChartView alloc]initWithFrame:CGRectMake(, , self.view.bounds.size.width, )];
lineChart.dataSource=self;
[self.view addSubview:lineChart];
}
-(NSInteger)numberForChart:(LineChartView *)chart
{
return _points.count;
}
-(float)chart:(LineChartView *)chart valueAtIndex:(NSInteger)index
{
return [[_points objectAtIndex:index] floatValue];
}
-(NSString *)chart:(LineChartView *)chart titleForXLabelAtIndex:(NSInteger)index
{
return [NSString stringWithFormat:@"10%ld",index];
}
-(BOOL)chart:(LineChartView *)chart backGroundColorAtXPointIndex:(NSInteger)index
{
) {
return true;
}
else
{
return false;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
效果:


IOS折线图的更多相关文章
- iOS 折线图、柱状图的简单实现
首先我得感谢某位博主,非常抱歉,因为之前直接下载博主提供这篇文章的demo,然后去研究了,没记住博主的名字.再次非常感谢. 而这个dome我又修改了一些,完善了一些不美观的bug,当然还有,后面会陆续 ...
- IOS折线图二
上周把项目的折线图给做了下,今天想着把它完善完善,自己设置了不同的数据源来测试,哈哈,还真遇到问题了, 就是给图表设置折点数为0时,视图显示的还是原来的,由于数据为空,应该将其设置为空,所以想着怎么把 ...
- iOS 折线图实现
图表绘制的过程实际上是坐标位置的计算过程,至于画线只要有了position,通过CAShapeLayer+BezierPath很快就可以画出来,这里提供一个绘制折线的demo,贵在思路,有需要的可以参 ...
- 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定义 : 贝赛尔曲线的每一个顶点都有两个控制点,用于控制在该顶点两侧的曲线的弧度. 曲线的定义有四个点:起始点 ...
随机推荐
- windows服务安装记录
首先打开cmd. 进入这个地址 C:\Windows\Microsoft.NET\Framework\v4.0.30319 执行操作 InstallUtil.exe E:\QueueWinServi ...
- UWP开发砸手机系列(二)—— “讲述人”识别自定义控件Command
上一篇我们提到如何让“讲述人”读出自定义的CanReadGrid,但“讲述人”仍然无法识别CanReadGrid上绑定的Command.XAML代码如下: <StackPanel> < ...
- HBase – 存储文件HFile结构解析
本文由 网易云发布. 作者:范欣欣 本篇文章仅限内部分享,如需转载,请联系网易获取授权. HFile是HBase存储数据的文件组织形式,参考BigTable的SSTable和Hadoop的TFile ...
- leetcode 74 搜索二维矩阵 java
题目: 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值.该矩阵具有如下特性: 每行中的整数从左到右按升序排列. 每行的第一个整数大于前一行的最后一个整数. 示例 1: 输入: mat ...
- python中多线程,多进程,多协程概念及编程上的应用
1, 多线程 线程是进程的一个实体,是CPU进行调度的最小单位,他是比进程更小能独立运行的基本单位. 线程基本不拥有系统资源,只占用一点运行中的资源(如程序计数器,一组寄存器和栈),但是它可以与同属于 ...
- AsyncTask的工作原理
AsyncTask是Android本身提供的一种轻量级的异步任务类.它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程更新UI.实际上,AsyncTask内部是封装了Thread和 ...
- sublime text 显示 typescript高亮
用ionic angular2写东西,还是用我的sublime 发现ts文件不识别,没有高亮.搜呗. 搜索出来的博客地址:http://www.cnblogs.com/happen-/p/638553 ...
- 【C++对象模型】使用gcc、clang和VC++显示C++类的内存布局
引言 各种C++实现对C++类/对象的内存布局可能有所不同,包括数据成员的顺序.虚函数表(virtual table: vtbl)的结构.继承关系的处理等.了解C++类/对象的布局,对于理解C++各种 ...
- Lucene7.4学习和简单使用
简述: 前面从新回顾学习了Solr,正好也借此机会顺便学习一下Lucene. 一.什么是Lucene? 全文检索的一个实现方式,也是非结构化数据查询的方法.应用场景:在数据量大,数据结构不固定的时候, ...
- 栈的理解和代码实现(java)
从数据结构的角度来看,其实栈也是线性表.特殊性在于栈和队列的基本操作是线性表操作的子集,栈是操作受限制的线性表. 栈的定义 栈是限定仅在表尾进行插入或者删除操作的线性表.对于一个栈来说,表尾端有着特殊 ...