iOS可复用控件之折线图
2017-10-13 14:27
204 查看
GitHub地址:https://github.com/runThor/HTChart
可支持左右拖动、双指放大缩小操作。
学习过PNChart的源码,这里是一个最基础、很简化的折线图。
效果:
实现:
折线类:
// HTLine.h
#import <UIKit/UIKit.h>
@interface HTLine : UIView
@property (nonatomic, strong) NSMutableArray *dataArr; // 此条折线的数据
@property (nonatomic, strong) UIColor *lineColor; // 此条折线的颜色
@end
图表类:
// HTChartView.h
#import <UIKit/UIKit.h>
#import "HTLine.h"
@interface HTChartView : UIView
@property (nonatomic, assign) CGFloat maxValue; // y轴的上限值
@property (nonatomic, assign) CGFloat minValue; // y轴的下限值
- (void)addLines:(NSArray *)lines; // 往图表中添加折线
@end
使用:
// ViewController.m
#import "ViewController.h"
#import "HTChartView.h"
@interface ViewController ()
@property (nonatomic, strong)HTChartView *chartView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化图表
self.chartView = [[HTChartView alloc] initWithFrame:CGRectMake(0, 0, 320, 250)];
self.chartView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
[self.chartView setCenter:CGPointMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/2)];
self.chartView.maxValue = 10;
self.chartView.minValue = 0;
[self.view addSubview:self.chartView];
// 添加折线
[self addLines];
}
// 模拟折线数据
- (void)addLines {
HTLine *yellowLine = [[HTLine alloc] init];
[yellowLine.dataArr addObjectsFromArray:@[@(1), @(3), @(5), @(7), @(9), @(5), @(6), @(4), @(2), @(8), @(1), @(6), @(4), @(5), @(9), @(8), @(2)]];
yellowLine.lineColor = [UIColor yellowColor];
HTLine *redLine = [[HTLine alloc] init];
[redLine.dataArr addObjectsFromArray:@[@(2), @(4), @(5), @(8), @(6), @(1), @(7), @(5), @(3), @(4), @(6), @(2), @(8), @(7), @(9), @(5), @(2)]];
redLine.lineColor = [UIColor redColor];
NSArray *linesArr = @[yellowLine, redLine];
[self.chartView addLines:linesArr];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
可支持左右拖动、双指放大缩小操作。
学习过PNChart的源码,这里是一个最基础、很简化的折线图。
效果:
实现:
折线类:
// HTLine.h
#import <UIKit/UIKit.h>
@interface HTLine : UIView
@property (nonatomic, strong) NSMutableArray *dataArr; // 此条折线的数据
@property (nonatomic, strong) UIColor *lineColor; // 此条折线的颜色
@end
// HTLine.m #import "HTLine.h" @implementation HTLine - (instancetype)init { if (self = [super init]) { self.dataArr = [[NSMutableArray alloc] init]; } return self; } @end
图表类:
// HTChartView.h
#import <UIKit/UIKit.h>
#import "HTLine.h"
@interface HTChartView : UIView
@property (nonatomic, assign) CGFloat maxValue; // y轴的上限值
@property (nonatomic, assign) CGFloat minValue; // y轴的下限值
- (void)addLines:(NSArray *)lines; // 往图表中添加折线
@end
// HTChartView.m #import "HTChartView.h" #define VIEW_WIDTH self.frame.size.width #define VIEW_HEIGHT self.frame.size.height #define MAX_POINT_INTERVAL 60 // 左右相邻点最大间隔,控制放大极限 #define MIN_POINT_INTERVAL 5 // 左右相邻点最小间隔,控制缩小极限 @interface HTChartView () @property (nonatomic, assign) CGFloat topMargin; // 与屏幕上边距 @property (nonatomic, assign) CGFloat bottomMargin; // 与屏幕下边距 @property (nonatomic, assign) CGFloat leftMargin; // 与屏幕左边距 @property (nonatomic, assign) CGFloat rightMargin; // 与屏幕右边距 @property (nonatomic, assign) NSInteger horizontalValueLinesCount; // 从y轴刻度处延伸出x轴水平线的数量,即y轴上的刻度个数 @property (nonatomic, assign) CGFloat contentOffset; // 折线图的偏移量,正数,最小为0 @property (nonatomic, assign) CGFloat pointInterval; // 左右相邻数据点的间隔 @property (nonatomic, strong) NSMutableArray *linesArr; // 所有折线 @property (nonatomic, strong) NSMutableArray *dataOriginArr; // 所有折线的数据点位置 @end @implementation HTChartView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1]; // 设置图表的初始状态 self.topMargin = 20.0; self.bottomMargin = 20.0; self.leftMargin = 30.0; self.rightMargin = 10.0; self.horizontalValueLinesCount = 5; self.pointInterval = 40; self.linesArr = [[NSMutableArray alloc] init]; } return self; } - (void)drawRect:(CGRect)rect { // 绘制图表框架 [self drawChartFrame]; // 绘制折线 [self drawLines]; } // 绘制图表框架 - (void)drawChartFrame { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor); // 画y轴 CGContextMoveToPoint(context, self.leftMargin, self.topMargin); CGContextAddLineToPoint(context, self.leftMargin, VIEW_HEIGHT - self.bottomMargin); // 画x轴 CGContextAddLineToPoint(context, VIEW_WIDTH - self.rightMargin, VIEW_HEIGHT - self.bottomMargin); // 画右边框 CGContextAddLineToPoint(context, VIEW_WIDTH - self.rightMargin, self.topMargin); // 绘制 CGContextStrokePath(context); // 绘制x轴的水平线 CGContextSetRGBStrokeColor(context, 1, 1, 1, 0.3); CGFloat eachHeight = (VIEW_HEIGHT - self.topMargin - self.bottomMargin)/(self.horizontalValueLinesCount + 1); for (int i = 1 ; i <= self.horizontalValueLinesCount; i++) { CGContextMoveToPoint(context, self.leftMargin, self.topMargin + eachHeight * i); CGContextAddLineToPoint(context, VIEW_WIDTH - self.rightMargin, self.topMargin + eachHeight * i); } CGContextStrokePath(context); } // 绘制折线 - (void)drawLines { CGContextRef context = UIGraphicsGetCurrentContext(); for (int lineIndex = 0; lineIndex < self.linesArr.count; lineIndex++) { HTLine *line = self.linesArr[lineIndex]; // 计算数据点位置 NSMutableArray *originArr = [[NSMutableArray alloc] init]; for (int dataIndex = 0; dataIndex < line.dataArr.count; dataIndex++) { CGFloat x = self.leftMargin + dataIndex * self.point a936 Interval - self.contentOffset; CGFloat y = VIEW_HEIGHT - ([line.dataArr[dataIndex] floatValue]/(self.maxValue - self.minValue) * (VIEW_HEIGHT - self.topMargin - self.bottomMargin) + self.bottomMargin); [originArr addObject:NSStringFromCGPoint(CGPointMake(x, y))]; } [self.dataOriginArr addObject:originArr]; // 绘制数据点 CGContextSetFillColorWithColor(context, line.lineColor.CGColor); for (NSString *origin in originArr) { CGPoint dataOrigin = CGPointFromString(origin); if (dataOrigin.x >= self.leftMargin) { if (dataOrigin.x > VIEW_WIDTH - self.rightMargin) { break; } else { CGContextFillEllipseInRect(context, CGRectMake(dataOrigin.x - 2.5, dataOrigin.y - 2.5, 5, 5)); } } } // 各数据点连成折线 CGContextSetStrokeColorWithColor(context, line.lineColor.CGColor); BOOL startDrawing = NO; for (int dataIndex = 0; dataIndex < originArr.count; dataIndex++) { CGPoint dataOrigin = CGPointFromString(originArr[dataIndex]); if (startDrawing == NO) { if (dataOrigin.x >= self.leftMargin) { if (dataIndex == 0) { CGContextMoveToPoint(context, dataOrigin.x, dataOrigin.y); } else { // 与y轴的交点 CGPoint lastDataOrigin = CGPointFromString(originArr[dataIndex - 1]); CGFloat startPointY = dataOrigin.y - (dataOrigin.x - self.leftMargin)/self.pointInterval * (dataOrigin.y - lastDataOrigin.y); CGContextMoveToPoint(context, self.leftMargin, startPointY); CGContextAddLineToPoint(context, dataOrigin.x, dataOrigin.y); } startDrawing = YES; } } else { if (dataOrigin.x >= VIEW_WIDTH - self.rightMargin) { // 与右边框的交点 CGPoint lastDataOrigin = CGPointFromString(originArr[dataIndex - 1]); CGFloat endPointY = dataOrigin.y - (dataOrigin.x - (VIEW_WIDTH - self.rightMargin))/self.pointInterval * (dataOrigin.y - lastDataOrigin.y); CGContextAddLineToPoint(context, VIEW_WIDTH - self.rightMargin, endPointY); break; } else { CGContextAddLineToPoint(context, dataOrigin.x, dataOrigin.y); } } } CGContextStrokePath(context); } } // 往图表中添加折线 - (void)addLines:(NSArray *)lines { [self.linesArr addObjectsFromArray:lines]; [self setNeedsDisplay]; } - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { CGFloat lineLength = self.pointInterval * ([self.linesArr[0] dataArr].count - 1); NSArray *touchesArr = [event allTouches].allObjects; // 单指拖动时,改变折线图偏移量 if (1 == touchesArr.count) { CGPoint currentTouchPoint = [[touches anyObject] locationInView:self]; CGPoint previousTouchPoint = [[touches anyObject] previousLocationInView:self]; self.contentOffset += previousTouchPoint.x - currentTouchPoint.x; } else if (2 == touchesArr.count) { // 双指缩放时,改变图表偏移量及相邻点间隔 CGPoint currentOnePoint = [touchesArr[0] locationInView:self]; CGPoint currentAnotherPoint = [touchesArr[1] locationInView:self]; CGPoint previousOnePoint = [touchesArr[0] previousLocationInView:self]; CGPoint previousAnotherPoint = [touchesArr[1] previousLocationInView:self]; CGFloat currentFingerSpacing = fabs(currentOnePoint.x - currentAnotherPoint.x); CGFloat previousFingerSpacing = fabs(previousOnePoint.x - previousAnotherPoint.x); CGFloat centerX = (currentOnePoint.x - currentAnotherPoint.x)/2 + currentAnotherPoint.x; if (currentFingerSpacing > previousFingerSpacing && self.pointInterval < MAX_POINT_INTERVAL) { // 放大 self.pointInterval *= 1.05; self.contentOffset = self.contentOffset * 1.05 + (centerX - self.leftMargin) * 0.05; } else if (currentFingerSpacing < previousFingerSpacing && self.pointInterval > MIN_POINT_INTERVAL) { // 缩小 self.pointInterval *= 0.95; self.contentOffset = self.contentOffset * 0.95 - (centerX - self.leftMargin) * 0.05; } } // 控制折线图偏移极限 if (self.contentOffset < 0) { self.contentOffset = 0; } else if (self.contentOffset > lineLength) { self.contentOffset = lineLength; } // 刷新折线图 [self setNeedsDisplay]; }
使用:
// ViewController.m
#import "ViewController.h"
#import "HTChartView.h"
@interface ViewController ()
@property (nonatomic, strong)HTChartView *chartView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化图表
self.chartView = [[HTChartView alloc] initWithFrame:CGRectMake(0, 0, 320, 250)];
self.chartView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
[self.chartView setCenter:CGPointMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/2)];
self.chartView.maxValue = 10;
self.chartView.minValue = 0;
[self.view addSubview:self.chartView];
// 添加折线
[self addLines];
}
// 模拟折线数据
- (void)addLines {
HTLine *yellowLine = [[HTLine alloc] init];
[yellowLine.dataArr addObjectsFromArray:@[@(1), @(3), @(5), @(7), @(9), @(5), @(6), @(4), @(2), @(8), @(1), @(6), @(4), @(5), @(9), @(8), @(2)]];
yellowLine.lineColor = [UIColor yellowColor];
HTLine *redLine = [[HTLine alloc] init];
[redLine.dataArr addObjectsFromArray:@[@(2), @(4), @(5), @(8), @(6), @(1), @(7), @(5), @(3), @(4), @(6), @(2), @(8), @(7), @(9), @(5), @(2)]];
redLine.lineColor = [UIColor redColor];
NSArray *linesArr = @[yellowLine, redLine];
[self.chartView addLines:linesArr];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
相关文章推荐
- iOS可复用控件之悬浮按钮
- iOS可复用控件之分段滚动控件HTSegmentedScrollView
- iOS使用xib文件创建一个组件为子控件,进行复用
- iOS可复用控件之发送动画
- iOS使用xib文件创建一个组件为子控件,进行复用
- iOS可复用控件之调节控件
- iOS可复用控件之修改SDCycleScrollView实现轮播图的缩放效果
- iOS可复用控件之表盘
- iOS可复用控件之滚动按钮组
- IOS开源项目(1)之RatingView星级评论控件学习
- iOS开发中使用Quartz2D绘图及自定义UIImageView控件
- IOS 自动填充视图控件长宽 笔记
- 论坛源码推荐(2月20日):适用于需要双Y轴场景的折线图 自定义的测量仪控件
- iOS UISegmentedControl控件详解
- iOS学习笔记-014.UIStepper——计数器控件
- iOS自定义控件之下拉列表按钮
- ios 获取控件相对屏幕的位置
- 基本控件文档-UISegment属性----iOS-Apple苹果官方文档翻译
- [iOS基础控件 - 6.0] UITableView
- iOS tableview复用时候崩溃