您好,欢迎来到花图问答。
搜索
您的当前位置:首页iOS绘图入门--手把手教你画折线图

iOS绘图入门--手把手教你画折线图

来源:花图问答

适用人群:iOS开发人员。
本文内容:使用UIBezierPath和CAShareLayer绘制简单的折线图。

平常,找个第三方的折线图,东改西改,很难做到设计图上的效果。与其折腾,还不如自己画个折线图好了,又省事又美观。其实画图也很简单,无非画路径、上颜色而已。
本文基于一个小例子讲解如何画简单的折线图,目录如下:
1.效果图展示
2.绘图思路入门
3.代码粘贴

1.1.效果图展示

先来展示下效果图:


2.绘图思路入门

就像画画一样,一步一步来。
(1)首先,给折线图区块定一个位置大小,这样方便绘制一些。这个区块的下边界即为x轴,左边界即为y轴,如下图所示:


chartX = LCSCREEN_WIDTH/375*60;
chartY = LCSCREEN_WIDTH/375*108;
chartWidth = LCSCREEN_WIDTH-chartX-15.0;
chartHeight = LineChartViewHeight - LCSCREEN_WIDTH/375*152;

(2)折线图区域定好了,就可以从绘制坐标轴开始了。坐标轴很简单,一条线搞定,三点一折线,代码如下:

// 绘制坐标轴
    UIBezierPath *axis = [[UIBezierPath alloc] init];
    [axis moveToPoint:CGPointMake(chartX, chartY)];//点1
    [axis addLineToPoint:CGPointMake(chartX, chartY+chartHeight)];//点2
    [axis addLineToPoint:CGPointMake(chartX+chartWidth, chartY+chartHeight)];//点3
    [COLOR_RGB(200, 200, 200) set];//折线色值
    [axis stroke];//画线

注意:UIBezierPath的绘制要在重写父类的方法- (void)drawRect:(CGRect)rect 中进行。如果不能再这里写,需要借助于CAShareLayer来做。这里举个栗子:

    // 绘制坐标轴
    UIBezierPath *axis = [[UIBezierPath alloc] init];
    [axis moveToPoint:CGPointMake(chartX, chartY)];
    [axis addLineToPoint:CGPointMake(chartX, chartY+chartHeight)];
    [axis addLineToPoint:CGPointMake(chartX+chartWidth, chartY+chartHeight)];
    
    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.strokeColor = COLOR_RGB(200, 200, 200).CGColor;
    layer.fillColor = [UIColor clearColor].CGColor;
    layer.path = axis;
    [self.layer addSublayer:layer];

(3)折线图好了,就可以画坐标轴上的刻度值了。
(4)然后画其他非图部分的控件。注意,控件的添加不能在- (void)drawRect:(CGRect)rect 中写,因为这个方法会调很多次,会导致重复创建控件。
(5)最后可以绘制折线。一般折线要根据传入的值来绘制,这里我随便弄了些随机数绘制折线。建议大家,弄些假数据一步步来,总体草图画出来后,效果实现了,再去优化代码,增加可配性,以及数据可变性。

3.代码粘贴

这里的代码只是随便画的草图,效果上述已展示。能画出草图,再去调优就简单多了。
该草图使用方法:

LineChartView *view = [LineChartView new];
view.backgroundColor = [UIColor whiteColor];
view.frame = CGRectMake(0, 100, self.view.bounds.size.width, LineChartViewHeight);
[self.view addSubview:view];

草图代码如下:
LineChartView.h

#import <UIKit/UIKit.h>

#define LCSCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define LCSCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
#define LineChartViewHeight (LCSCREEN_WIDTH/540*456)

@interface LineChartView : UIView

@end

LineChartView.m


#import "LineChartView.h"

#define COLOR_RGB(r,g,b) [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f alpha:1.0]

@interface LineChartView ()
{
    CGFloat chartX;
    CGFloat chartY;
    CGFloat chartWidth;
    CGFloat chartHeight;
    
    CGFloat popoverWidth;
    CGFloat popoverHeight;
}
@property (nonatomic, strong) UIView *popoverView;
@property (nonatomic, strong) UILabel *popoverLbl;
@property (nonatomic, strong) UIView *currLineView;
@end

@implementation LineChartView

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.backgroundColor = [UIColor whiteColor];
        chartX = LCSCREEN_WIDTH/375*60;
        chartY = LCSCREEN_WIDTH/375*108;
        chartWidth = LCSCREEN_WIDTH-chartX-15.0;
        chartHeight = LineChartViewHeight - LCSCREEN_WIDTH/375*152;
        popoverWidth = 100;
        popoverHeight = 60;
        
        UILabel *titleLbl = [UILabel new];
        titleLbl.frame = CGRectMake(10.0, 15.0, 200, 30.0);
        titleLbl.textColor = [UIColor blackColor];
        titleLbl.font = [UIFont systemFontOfSize:18.0];
        titleLbl.text = @"工况发布趋势图";
        [self addSubview:titleLbl];
        
        CGFloat itemWidth = 50.0;
        for (int i=0; i<4; i++) {
            UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
            btn.frame = CGRectMake(LCSCREEN_WIDTH-(itemWidth+5.0)*(i+1), 15.0, itemWidth, 30.0);
            [btn setTitle:@"日" forState:UIControlStateNormal];
            btn.backgroundColor = [UIColor lightGrayColor];
            btn.layer.cornerRadius = 15.0;
            btn.layer.masksToBounds = YES;
            [self addSubview:btn];
        }
        
        NSArray *colorArr = @[[UIColor redColor], [UIColor cyanColor], [UIColor greenColor], [UIColor blueColor]];
        for (int i=0; i<colorArr.count; i++) {
            UIView *view = [UIView new];
            view.frame = CGRectMake(LCSCREEN_WIDTH-(itemWidth+5.0)*(i+1), 60.0, itemWidth, 30.0);
            [self addSubview:view];
            
            UIView *point = [UIView new];
            point.backgroundColor = colorArr[i];
            point.frame = CGRectMake(0, 10, 10, 10);
            point.layer.cornerRadius = 5;
            point.layer.masksToBounds = YES;
            [view addSubview:point];
            
            UILabel *lab = [UILabel new];
            lab.frame = CGRectMake(15, 0, itemWidth-15, 30);
            lab.text = @"文明";
            lab.textColor = [UIColor lightGrayColor];
            lab.font = [UIFont systemFontOfSize:14];
            [view addSubview:lab];
        }
        
    }
    return self;
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];
    
    UITouch *touch = [[touches allObjects] firstObject];
    CGFloat currX = [touch locationInView:self].x - chartX;
    
    // 可触控范围
    CGFloat canMinX = 0;
    CGFloat canMaxX = chartWidth;
    if (currX < canMinX || currX > canMaxX) {
        return;//超出范围
    }
    
    int i = roundf(currX*(30)/canMaxX);//四舍五入
    NSLog(@"------%d", i);
    self.popoverLbl.text = [NSString stringWithFormat:@"%d数据", i];
    
    // 调整popover和线的位置
    CGFloat popoverX = chartX+currX-popoverWidth/2;
    if (popoverX > LCSCREEN_WIDTH-popoverWidth) {
        popoverX = LCSCREEN_WIDTH-popoverWidth;
    }
    self.popoverView.hidden = NO;
    CGRect rect = self.popoverView.frame;
    rect.origin = CGPointMake(popoverX, chartY-10-popoverHeight);
    self.popoverView.frame = rect;
    
    CGFloat popoverLineX = chartX+currX;
    if (popoverLineX > LCSCREEN_WIDTH-15.0) {
        popoverLineX = LCSCREEN_WIDTH-15.0;
    }
    self.currLineView.hidden = NO;
    CGRect rect1 = self.currLineView.frame;
    rect1.origin = CGPointMake(popoverLineX, chartY-10);
    self.currLineView.frame = rect1;
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    
    self.popoverView.hidden = YES;
    self.currLineView.hidden = YES;
}


// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // 绘制坐标轴
    UIBezierPath *axis = [[UIBezierPath alloc] init];
    [axis moveToPoint:CGPointMake(chartX, chartY)];
    [axis addLineToPoint:CGPointMake(chartX, chartY+chartHeight)];
    [axis addLineToPoint:CGPointMake(chartX+chartWidth, chartY+chartHeight)];
    [COLOR_RGB(200, 200, 200) set];//COLOR_RGB(239, 244, 246)
    [axis stroke];
    
    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.strokeColor = COLOR_RGB(200, 200, 200).CGColor;
    layer.fillColor = [UIColor clearColor].CGColor;
    layer.path = axis;
    [self.layer addSublayer:layer];
    
    // 绘制Y坐标值
    NSArray *arr = @[@(0), @(50), @(150), @(250), @(350), @(450)];
    CGFloat YItemHeight = chartHeight/6;
    for (int i=1; i<=6; i++) {
        UILabel *lab = [UILabel new];
        lab.textColor = [UIColor grayColor];
        lab.font = [UIFont systemFontOfSize:14];
        lab.textAlignment = NSTextAlignmentRight;
        lab.frame = CGRectMake(15.0, chartY+chartHeight-YItemHeight*i, chartX-20.0, YItemHeight);
        lab.text = [NSString stringWithFormat:@"%@", arr[i-1]];
        [self addSubview:lab];
    }
    
    // 绘制X坐标值
    UILabel *blab = [UILabel new];
    blab.frame = CGRectMake(chartX, chartY+chartHeight+5, 100, 30.0);
    blab.textColor = [UIColor grayColor];
    blab.font = [UIFont systemFontOfSize:14];
    blab.text = @"2015-11-01";
    [self addSubview:blab];
    UILabel *elab = [UILabel new];
    elab.frame = CGRectMake(chartX+chartWidth-100, chartY+chartHeight+5, 100, 30.0);
    elab.textColor = [UIColor grayColor];
    elab.font = [UIFont systemFontOfSize:14];
    elab.textAlignment = NSTextAlignmentRight;
    elab.text = @"2018-11-30";
    [self addSubview:elab];
    
    // 绘制虚线
    for (int i=0; i<6; i++) {
        CGFloat lineY = chartY+YItemHeight/2+YItemHeight*i;
        UIBezierPath *line = [UIBezierPath bezierPath];
        [line moveToPoint:CGPointMake(chartX, lineY)];
        [line addLineToPoint:CGPointMake(chartX+chartWidth, lineY)];
        [line setLineWidth:1];
        CGFloat dashPattern[] = {2,1};// 3实线,1空白
        [line setLineDash:dashPattern count:1 phase:1];
        [COLOR_RGB(239, 244, 246) setStroke];
        [line stroke];
    }
    
    // 绘制数据线
    NSArray<UIColor *> *colorArr = @[[UIColor redColor], [UIColor cyanColor], [UIColor greenColor], [UIColor blueColor]];
    for (int i=0; i<colorArr.count; i++) {
        UIBezierPath *line = [UIBezierPath bezierPath];
        
        for (int j=0; j<=30; j++) {
            CGFloat offsetX = chartWidth/30*j;
            CGFloat randomNum = 80*(i+1)+arc4random()%80;
            CGFloat offsetY = chartHeight-(randomNum)*chartHeight/450;
            if (j==0) {
                [line moveToPoint:CGPointMake(chartX, chartY+offsetY)];
            } else {
                [line addLineToPoint:CGPointMake(chartX+offsetX, chartY+offsetY)];
            }
        }
        
        [line setLineWidth:1];
        [colorArr[i] set];
        [line stroke];
    }
    
}

- (UIView *)popoverView {
    if (!_popoverView) {
        _popoverView = [UIView new];
        _popoverView.frame = CGRectMake(0, 0, popoverWidth, popoverHeight);
        _popoverView.backgroundColor = [UIColor grayColor];
        [self addSubview:_popoverView];
        
        UILabel *lab = [UILabel new];
        lab.frame = _popoverView.frame;
        lab.textAlignment = NSTextAlignmentCenter;
        lab.textColor = [UIColor whiteColor];
        [_popoverView addSubview:lab];
        _popoverLbl = lab;
    }
    return _popoverView;
}

- (UIView *)currLineView {
    if (!_currLineView) {
        _currLineView = [UIView new];
        _currLineView.frame = CGRectMake(0, 0, 1.0, chartHeight+10.0);
        _currLineView.backgroundColor = [UIColor grayColor];
        [self addSubview:_currLineView];
    }
    return _currLineView;
}

@end

Copyright © 2019- huatuowenda.com 版权所有 湘ICP备2023022495号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务