最近项目上有一个折线图的需求,根据实际的产品需求、面向服务器接口数据手撸了一个,自己写随意玩=。=
PXLineChart
-
更新(17-12-20)-支持y轴数据不等分
Demo地址:
OC版本PXLineChart_OC
Swift版本PXLineChart_Swift
使用
为了最大化的可定制,基于UITableView delegate设计模式来提供对外接口
#import "ViewController.h"
#import "PXLineChartView.h"
#import "PointItem.h"
@interface ViewController ()
@property (nonatomic, weak) IBOutlet PXLineChartView *pXLineChartView;
@property (nonatomic, strong) NSArray *lines;//line count
@property (nonatomic, strong) NSArray *xElements;//x轴数据
@property (nonatomic, strong) NSArray *yElements;//y轴数据
@end
#pragma mark -
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_pXLineChartView.delegate = self;
_xElements = @[@"16-2",@"16-3",@"16-4",@"16-5",@"16-6",@"16-7",@"16-8",@"16-9",@"16-10",@"16-11",@"16-12",@"17-01",@"17-02",@"17-03",@"17-04",@"17-05"];
_yElements = @[@"1000",@"2000",@"3000",@"4000",@"5000"];
self.lines = [self lines:NO];
// Do any additional setup after loading the view, typically from a nib.
}
- (NSArray *)lines:(BOOL)fill {
NSArray *pointsArr = @[@{@"xValue" : @"16-2", @"yValue" : @"1000"},
@{@"xValue" : @"16-4", @"yValue" : @"2000"},
@{@"xValue" : @"16-6", @"yValue" : @"1700"},
@{@"xValue" : @"16-8", @"yValue" : @"3100"},
@{@"xValue" : @"16-9", @"yValue" : @"3500"},
@{@"xValue" : @"16-12", @"yValue" : @"3400"},
@{@"xValue" : @"17-02", @"yValue" : @"1100"},
@{@"xValue" : @"17-04", @"yValue" : @"1500"}];
NSArray *pointsArr1 = @[@{@"xValue" : @"16-2", @"yValue" : @"2000"},
@{@"xValue" : @"16-3", @"yValue" : @"2200"},
@{@"xValue" : @"16-4", @"yValue" : @"3000"},
@{@"xValue" : @"16-6", @"yValue" : @"3750"},
@{@"xValue" : @"16-7", @"yValue" : @"3800"},
@{@"xValue" : @"16-8", @"yValue" : @"4000"},
@{@"xValue" : @"16-10", @"yValue" : @"2000"}];
NSMutableArray *points = @[].mutableCopy;
for (int i = 0; i < pointsArr.count; i++) {
PointItem *item = [[PointItem alloc] init];
NSDictionary *itemDic = pointsArr[i];
item.price = itemDic[@"yValue"];
item.time = itemDic[@"xValue"];
item.chartLineColor = [UIColor redColor];
item.chartPointColor = [UIColor redColor];
item.pointValueColor = [UIColor redColor];
if (fill) {
item.chartFillColor = [UIColor colorWithRed:0 green:0.5 blue:0.2 alpha:0.5];
item.chartFill = YES;
}
[points addObject:item];
}
NSMutableArray *pointss = @[].mutableCopy;
for (int i = 0; i < pointsArr1.count; i++) {
PointItem *item = [[PointItem alloc] init];
NSDictionary *itemDic = pointsArr1[i];
item.price = itemDic[@"yValue"];
item.time = itemDic[@"xValue"];
item.chartLineColor = [UIColor colorWithRed:0.2 green:1 blue:0.7 alpha:1];
item.chartPointColor = [UIColor colorWithRed:0.2 green:1 blue:0.7 alpha:1];
item.pointValueColor = [UIColor colorWithRed:0.2 green:1 blue:0.7 alpha:1];
if (fill) {
item.chartFillColor = [UIColor colorWithRed:0.5 green:0.1 blue:0.8 alpha:0.5];
item.chartFill = YES;
}
[pointss addObject:item];
}
//两条line
return @[pointss,points];
}
#pragma mark PXLineChartViewDelegate
//通用设置
- (NSDictionary *)lineChartViewAxisAttributes {
return @{yElementInterval : @"40",
xElementInterval : @"40",
yMargin : @"50",
xMargin : @"25",
yAxisColor : [UIColor colorWithRed:200.0/255 green:200.0/255 blue:200.0/255 alpha:1],
xAxisColor : [UIColor colorWithRed:200.0/255 green:200.0/255 blue:200.0/255 alpha:1],
gridColor : [UIColor colorWithRed:244.0/255 green:244.0/255 blue:244.0/255 alpha:1],
gridHide : @0,
pointHide : @0,
pointFont : [UIFont systemFontOfSize:10]};
}
//line count
- (NSUInteger)numberOfChartlines {
return self.lines.count;
}
//x轴y轴对应的元素count
- (NSUInteger)numberOfElementsCountWithAxisType:(AxisType)axisType {
return (axisType == AxisTypeY)? _yElements.count : _xElements.count;
}
//x轴y轴对应的元素view
- (UILabel *)elementWithAxisType:(AxisType)axisType index:(NSUInteger)index {
UILabel *label = [[UILabel alloc] init];
NSString *axisValue = @"";
if (axisType == AxisTypeX) {
axisValue = _xElements[index];
label.textAlignment = NSTextAlignmentCenter;//;
}else if(axisType == AxisTypeY){
axisValue = _yElements[index];
label.textAlignment = NSTextAlignmentRight;//;
}
label.text = axisValue;
label.font = [UIFont systemFontOfSize:12];
label.textColor = [UIColor blackColor];
return label;
}
//每条line对应的point数组
- (NSArray> *)plotsOflineIndex:(NSUInteger)lineIndex {
return self.lines[lineIndex];
}
//点击point回调响应
- (void)elementDidClickedWithPointSuperIndex:(NSUInteger)superidnex pointSubIndex:(NSUInteger)subindex {
PointItem *item = self.lines[superidnex][subindex];
NSString *xTitle = item.time;
NSString *yTitle = item.price;
UIAlertController *alertView = [UIAlertController alertControllerWithTitle:yTitle
message:[NSString stringWithFormat:@"x:%@ \ny:%@",xTitle,yTitle] preferredStyle:UIAlertControllerStyleAlert];
[alertView addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}]];
[self presentViewController:alertView animated:YES completion:nil];
}
static bool fill = NO;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
fill = !fill;
self.lines = [self lines:fill];
[_pXLineChartView reloadData];
}
数据源三组:X轴、Y轴、真正的折线数组lines
X\Y轴对应的NSString数组,lines对应的二维数组
着重看下lines的数据结构
NSArray *pointsArr = @[@{@"xValue" : @"16-2", @"yValue" : @"1000"},
@{@"xValue" : @"16-4", @"yValue" : @"2000"},
@{@"xValue" : @"16-6", @"yValue" : @"1700"},
@{@"xValue" : @"16-8", @"yValue" : @"3100"},
@{@"xValue" : @"16-9", @"yValue" : @"3500"},
@{@"xValue" : @"16-12", @"yValue" : @"3400"},
@{@"xValue" : @"17-02", @"yValue" : @"1100"},
@{@"xValue" : @"17-04", @"yValue" : @"1500"}];
NSArray *pointsArr1 = @[@{@"xValue" : @"16-2", @"yValue" : @"2000"},
@{@"xValue" : @"16-3", @"yValue" : @"2200"},
@{@"xValue" : @"16-4", @"yValue" : @"3000"},
@{@"xValue" : @"16-6", @"yValue" : @"3750"},
@{@"xValue" : @"16-7", @"yValue" : @"3800"},
@{@"xValue" : @"16-8", @"yValue" : @"4000"},
@{@"xValue" : @"16-10", @"yValue" : @"2000"}];
NSMutableArray *points = @[].mutableCopy;
for (int i = 0; i < pointsArr.count; i++) {
PointItem *item = [[PointItem alloc] init];
NSDictionary *itemDic = pointsArr[i];
item.price = itemDic[@"yValue"];
item.time = itemDic[@"xValue"];
item.chartLineColor = [UIColor redColor];
item.chartPointColor = [UIColor redColor];
item.pointValueColor = [UIColor redColor];
if (fill) {
item.chartFillColor = [UIColor colorWithRed:0 green:0.5 blue:0.2 alpha:0.5];
item.chartFill = YES;
}
[points addObject:item];
}
NSMutableArray *pointss = @[].mutableCopy;
for (int i = 0; i < pointsArr1.count; i++) {
PointItem *item = [[PointItem alloc] init];
NSDictionary *itemDic = pointsArr1[i];
item.price = itemDic[@"yValue"];
item.time = itemDic[@"xValue"];
item.chartLineColor = [UIColor colorWithRed:0.2 green:1 blue:0.7 alpha:1];
item.chartPointColor = [UIColor colorWithRed:0.2 green:1 blue:0.7 alpha:1];
item.pointValueColor = [UIColor colorWithRed:0.2 green:1 blue:0.7 alpha:1];
if (fill) {
item.chartFillColor = [UIColor colorWithRed:0.5 green:0.1 blue:0.8 alpha:0.5];
item.chartFill = YES;
}
[pointss addObject:item];
}
//两条line
return @[pointss,points];
lines数组里面装了两个子数组pointss、points,pointss\ points数组里面装的是我们自定义的model,此model必须实现协议PointItemProtocol
PointItemProtocol.h
@protocol PointItemProtocol
@required
- (NSString *)px_pointYvalue; //y坐标值
- (NSString *)px_pointXvalue; //x坐标值
@optional
- (UIColor *)px_chartLineColor;//折线color
- (UIColor *)px_chartPointColor;//point color
- (UIColor *)px_pointValueColor;//
- (CGSize)px_pointSize;//point size
- (UIColor *)px_chartFillColor;////fill color - UIColor
- (BOOL)px_chartFill;//是否fill - NSNumber(@1-fill; @0-不fill)
自定义model必须实现- (NSString *)px_pointYvalue;- (NSString *)px_pointXvalue; 分别对应的y、x值
@implementation PointItem
#pragma PointItemProtocol
- (NSString *)px_pointYvalue {
return _price;
}
- (NSString *)px_pointXvalue {
return _time;
}
- (UIColor *)px_chartLineColor {
return _chartLineColor;
}
- (UIColor *)px_chartPointColor {
return _chartPointColor;
}
- (UIColor *)px_pointValueColor {
return _pointValueColor;
}
- (UIColor *)px_chartFillColor {
return _chartFillColor;
}
- (BOOL)px_chartFill {
return _chartFill;
}
也就是对每条line的差异化配置都在里面,这个后续可以根据所需进行扩展;
通用化的配置在PXLineChartViewDelegate:
#pragma mark PXLineChartViewDelegate
//通用设置
- (NSDictionary *)lineChartViewAxisAttributes {
return @{yElementInterval : @"40",
xElementInterval : @"40",
yMargin : @"50",
xMargin : @"25",
yAxisColor : [UIColor colorWithRed:200.0/255 green:200.0/255 blue:200.0/255 alpha:1],
xAxisColor : [UIColor colorWithRed:200.0/255 green:200.0/255 blue:200.0/255 alpha:1],
gridColor : [UIColor colorWithRed:244.0/255 green:244.0/255 blue:244.0/255 alpha:1],
gridHide : @0,
pointHide : @0,
pointFont : [UIFont systemFontOfSize:10]};
}
所有通用化配置参数参见PXLineChartConst.h;后续可在里面进行自定义扩展
我们看下其他delegate 方法
//line count
- (NSUInteger)numberOfChartlines {
return self.lines.count;
}
返回折线个数
//x轴y轴对应的元素count
- (NSUInteger)numberOfElementsCountWithAxisType:(AxisType)axisType {
return (axisType == AxisTypeY)? _yElements.count : _xElements.count;
}
//x轴y轴对应的元素view
- (UILabel *)elementWithAxisType:(AxisType)axisType index:(NSUInteger)index {
UILabel *label = [[UILabel alloc] init];
NSString *axisValue = @"";
if (axisType == AxisTypeX) {
axisValue = _xElements[index];
label.textAlignment = NSTextAlignmentCenter;//;
}else if(axisType == AxisTypeY){
axisValue = _yElements[index];
label.textAlignment = NSTextAlignmentRight;//;
}
label.text = axisValue;
label.font = [UIFont systemFontOfSize:12];
label.textColor = [UIColor blackColor];
return label;
}
对X\Y轴元素视图定制
//每条line对应的point数组
- (NSArray> *)plotsOflineIndex:(NSUInteger)lineIndex {
return self.lines[lineIndex];
}
返回每条折线对应的点
以上是PXLineChartViewDelegate必须实现的方法
//点击point回调响应
- (void)elementDidClickedWithPointSuperIndex:(NSUInteger)superidnex pointSubIndex:(NSUInteger)subindex {
PointItem *item = self.lines[superidnex][subindex];
NSString *xTitle = item.time;
NSString *yTitle = item.price;
UIAlertController *alertView = [UIAlertController alertControllerWithTitle:yTitle
message:[NSString stringWithFormat:@"x:%@ \ny:%@",xTitle,yTitle] preferredStyle:UIAlertControllerStyleAlert];
[alertView addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}]];
[self presentViewController:alertView animated:YES completion:nil];
}
点击回调可选
我是分割线,但是没有线
如果我们想填充可以在设置PointItem的chartFill和chartFillColor属性
self.lines = [self lines:YES];
[_pXLineChartView reloadData];
类似UITableView我们可以对其刷新
[_pXLineChartView reloadData];
以上具体使用差不多说完了,实际开发中和服务器童鞋对接接口的时候返回的json model实现PointItemProtocol给x、y填值,具体参考demo,另外核心画线操作在PXChartBackgroundView类里,具体下载查看
Demo地址:
OC版本PXLineChart_OC
Swift版本PXLineChart_Swift
如果觉得还有用,欢迎star鼓励,我会不断扩展优化迭代。