IOS折线统计图

来源:互联网 发布:手机短信轰炸机源码 编辑:程序博客网 时间:2024/05/22 11:59

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


现在这个还有许多优化的地方:

1.一个表中只能画一个折线

2.目前的要求最小值为0,没考虑负数的最小值

////  LineChartView.h//  CAShapeLayerTest////  Created by Mkil on 3/31/16.//  Copyright © 2016 Mkil. All rights reserved.//#import <UIKit/UIKit.h>#define SPACING 70.0        //设置两点的水平间距#define BOTTOMSPACING 60.0  //底部距离#define LEFTSPACING 80.0   //左边距离//文本类型typedef NS_ENUM(NSInteger, TitleType) {    TitleForX,    TitleForPoint,    TitelForNormal};@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;@property (nonatomic, assign) NSInteger maxValue;@end
////  LineChartView.m//  CAShapeLayerTest////  Created by Mkil on 3/31/16.//  Copyright © 2016 Mkil. All rights reserved.//#import "LineChartView.h"#define textDColor [UIColor colorWithRed:255/255.0 green:164/255.0 blue:102/255.0 alpha:1]#define line228Color [UIColor colorWithRed:228/255.0 green:228/255.0 blue:228/255.0 alpha:1]@interface  LineChartView ()@property (nonatomic, strong) CAShapeLayer *linePath;@property (nonatomic, assign) NSInteger count;          //点数@property (nonatomic, assign) CGFloat avgHeight;        //刻度@end@implementation LineChartView- (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 = 2;        _linePath.fillColor = [UIColor clearColor].CGColor;                self.bounces=NO;//        self.backgroundColor = [UIColor lightGrayColor];        self.showsHorizontalScrollIndicator=NO;        self.showsVerticalScrollIndicator=NO;    }    return self;}//点数-(NSInteger)count{    return [_dataSource numberForChart:self];}//刻度-(CGFloat)avgHeight{    CGFloat height=self.frame.size.height;    _avgHeight=(height-40-20)/self.maxValue;    return _avgHeight;}- (void)drawRect:(CGRect)rect{        [super drawRect:rect];        NSInteger count = [self.layer.sublayers count];    for (int i = 0; i < count ; i ++) {                [self.layer.sublayers[i] removeFromSuperlayer];    }        //不能通过for in 删除  was mutated while being enumerated 遍历的时候不能删除    //    for (CALayer *layer in self.layer.sublayers) {    //        [layer removeFromSuperlayer];    //    }        if (self.count <= 0) {                return;    }        [self.layer addSublayer:_linePath];     self.contentSize=CGSizeMake((self.count)*SPACING + LEFTSPACING, self.bounds.size.height);       //画横线    [self drawTransverseLineHeight:self.frame.size.height - 40];    [self drawTransverseLineHeight:20];    [self drawTransverseLineHeight:20 + (self.frame.size.height - 40 - 20)/2.0];        //画文字    CGPoint point = CGPointMake(40, 20);        [self drawText:[NSString stringWithFormat:@"%ld",self.maxValue] withPoint:point withType:TitelForNormal withColor:line228Color withIndex:1];    point = CGPointMake(40, 20 + (self.frame.size.height - 40 - 20)/2.0);    [self drawText:[NSString stringWithFormat:@"%ld",self.maxValue/2] withPoint:point withType:TitelForNormal withColor:line228Color withIndex:1];    //画折线    [self drawBrokenLine];    }//画横线- (void)drawTransverseLineHeight:(CGFloat) height{    CAShapeLayer *layer=[CAShapeLayer layer];    layer.lineCap=kCALineCapRound;    layer.lineJoin=kCALineJoinBevel;    layer.lineWidth=0.1;    layer.fillColor=[UIColor clearColor].CGColor;    [self.layer addSublayer:layer];        UIBezierPath *transverseLine = [UIBezierPath bezierPath];    [transverseLine moveToPoint:CGPointMake(20, height)];    [transverseLine addLineToPoint:CGPointMake(self.contentSize.width - 20, height)];        layer.path = transverseLine.CGPath;    layer.strokeColor = [UIColor blackColor].CGColor;}//画竖线-(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)drawText:(NSString *)text withPoint:(CGPoint)point withType:(TitleType) type withColor:(UIColor *)textColor withIndex:(NSInteger)index{        CGRect frame=[text boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:10.f]} context:nil];        UILabel *label=[[UILabel alloc]init];        CGPoint pointForValueString=CGPointMake(point.x-15, point.y);    if (pointForValueString.y+frame.size.height>self.frame.size.height-50) {        pointForValueString.y=point.y-frame.size.height-20;    }    else if (pointForValueString.y-frame.size.height<0)    {        pointForValueString.y=point.y+frame.size.height-20;    }    label.frame=CGRectMake(pointForValueString.x - 15, pointForValueString.y, 60, 30);    label.textAlignment=NSTextAlignmentCenter;    if (type==TitleForPoint) {        label.textColor=textColor;        label.font=[UIFont systemFontOfSize:13.f];    }    else if (type==TitleForX)    {        label.frame=CGRectMake(pointForValueString.x, pointForValueString.y+15, 30,30);        if (_dataSource&&[_dataSource respondsToSelector:@selector(chart:backGroundColorAtXPointIndex:)]) {            if ([_dataSource chart:self backGroundColorAtXPointIndex:index]) {                label.backgroundColor=textColor;                label.textColor=[UIColor whiteColor];                label.layer.cornerRadius=label.bounds.size.width/2;                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:14.f];    }else if (type == TitelForNormal)    {        label.textColor=textColor;        label.font=[UIFont systemFontOfSize:18.f];    }    label.text=text;    [self addSubview:label];}- (void)drawBrokenLine{    UIBezierPath *path = [UIBezierPath bezierPath];    for (int i=0; i < self.count; i++) {                CGFloat value = [_dataSource chart:self valueAtIndex:i];        CGPoint point = [self pointWithValue:value index:i];            //画竖线        if (i == 0) {                        [self drawVerticalLineStartPoint:CGPointMake(LEFTSPACING, self.frame.size.height-40) withEndPoint:CGPointMake(LEFTSPACING, self.frame.size.height - 30) withColor:             [UIColor blueColor]];                        [self drawVerticalLineStartPoint:CGPointMake(LEFTSPACING, self.frame.size.height-40) withEndPoint:point withColor:             [UIColor blueColor]];        }else{                        [self drawVerticalLineStartPoint:CGPointMake(i*SPACING + LEFTSPACING, self.frame.size.height-40) withEndPoint:CGPointMake(i*SPACING + LEFTSPACING, self.frame.size.height - 30) withColor:             [UIColor blueColor]];                        [self drawVerticalLineStartPoint:CGPointMake(i*SPACING + LEFTSPACING, self.frame.size.height-40) withEndPoint:point withColor:             [UIColor blueColor]];        }                //画文字        NSString *valueString=[NSString stringWithFormat:@"%ld",(long)value];        [self drawText:valueString withPoint:point withType:TitleForPoint withColor:textDColor 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-10) withType:TitleForX withColor:line228Color withIndex:i];        }                //画折线        //贝塞尔曲线        if (i==0) {            [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 = 2;    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=textDColor.CGColor;    [_linePath addAnimation:pathAnimation forKey:@"strokeEndAnimation"];    _linePath.strokeEnd = 1.0;}//根据索引计算出折点的位置-(CGPoint)pointWithValue:(NSInteger)value index:(NSInteger)index{    CGFloat height=self.frame.size.height;        if (index == 0) {                return CGPointMake(LEFTSPACING, height-value*self.avgHeight-40);    }    return  CGPointMake(index*SPACING + LEFTSPACING, height-value*self.avgHeight-40);}@end

调用:

////  ViewController.m//  CAShapeLayerTest////  Created by Mkil on 3/31/16.//  Copyright © 2016 Mkil. All rights reserved.//#import "ViewController.h"#import "LineChartView.h"@interface ViewController ()<LineChartDataSource>@property (nonatomic ,strong) NSArray *points;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.            self.view.backgroundColor = [UIColor whiteColor];        _points=@[@3000,@400,@2500,@3500,@1800,@2800,@900,@3400,@2900,@3100,@3000,@2500];        LineChartView *lineChart=[[LineChartView alloc]initWithFrame:CGRectMake(0, 100, self.view.bounds.size.width, 300)];        lineChart.dataSource=self;    lineChart.maxValue = 4000;        [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:@"%ld",index*2];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end

效果:




1 0
原创粉丝点击