图形绘制

一.知识点

  1. Quartz2d 绘制直线,三角形 矩形 圆形 扇形
  2. Quartz2d 图表应用:柱状图 饼状图 折线图
  3. drawRect方法的触发,重绘机制
  4. 案例:下载进度条
  5. CoreGraphics核心框架之矩阵操作
  6. CoreGraphics核心框架之裁剪 水印 图层拷贝 上下文栈
  7. 案例:股市K线图

二.图形绘制

Quartz2d 绘制图形

//
//  Quartz.h

#import <UIKit/UIKit.h>
#define COLOR1 [UIColor colorWithRed:1.0  green:0.5 blue:0.31 alpha:1.0]
#define COLOR2 [UIColor colorWithRed:0.54  green:0.81 blue:0.96 alpha:1.0]
@interface Quartz : UIView

@end
//
//  Quartz.m


#import "Quartz.h"

@implementation Quartz

//1.必调  setNeedDisplay
- (void)drawRect:(CGRect)rect {
    //[self drawMyLine];    //直线
    //[self drawMyRect];    //矩形
    //[self drawMyPath1];   //非闭合三角形
    //[self drawMyPath2];   //闭合三角形
    //[self drawMyArc];     //任意弧形
    //[self drawMyArc1];    //波浪形
    //[self drawMyCircle];  //圆形
    //[self drawMyCircle1];   //弧形
    //[self drawMyProperty1];    //线条两端
    //[self drawMyProperty2]; //转折处属性设置
    //[self drawMyProperty3];   //虚线
    [self drawMyProperty4];     //条形码
}
//直线
-(void)drawMyLine {
    //1 获取绘图画板
    //2 画 属性
    //3 渲染
    CGContextRef context = UIGraphicsGetCurrentContext();
    //设置颜色
    [COLOR2 setStroke];
    CGContextSetLineWidth(context , 10.0);//当前线条宽度
    CGContextMoveToPoint(context, 100, 100);//绘制一个点
    CGContextAddLineToPoint(context, 300, 300);//另外一个点
    CGContextStrokePath(context);//渲染路径 
    
}

//矩形
-(void)drawMyRect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];//内部填充颜色
    [COLOR2 setStroke];//边框颜色 CGContextStrokePath(context)
    CGContextSetLineWidth(context , 10.0);//当前线条宽度
    CGContextAddRect(context, CGRectMake(100, 100, 200, 100));
//    CGContextStrokePath(context);//渲染路径 边框
//    CGContextFillPath(context);//填充
    CGContextDrawPath(context, kCGPathFillStroke);//边框+填充
    
}

//非闭合三角形(边框中有一个边没有颜色)
-(void)drawMyPath1 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];//内部填充颜色
    [COLOR2 setStroke];//边框颜色 CGContextStrokePath(context)
    CGContextSetLineWidth(context, 5.0);
    CGMutablePathRef pathRef = CGPathCreateMutable();//创建一个多路径
    CGPathMoveToPoint(pathRef , nil, 150, 150);//在路径上绘制一个起点
    CGPathAddLineToPoint(pathRef, nil, 300, 300);
    CGPathAddLineToPoint(pathRef, nil, 0, 300);
    CGContextAddPath(context, pathRef);
    CGContextDrawPath(context, kCGPathFillStroke);
}

//闭合 三角形
-(void)drawMyPath2 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];//内部填充颜色
    [COLOR2 setStroke];//边框颜色 CGContextStrokePath(context)
    CGContextSetLineWidth(context, 5.0);
    CGMutablePathRef pathRef = CGPathCreateMutable();//创建一个多路径
    CGPathMoveToPoint(pathRef , nil, 150, 150);//在路径上绘制一个起点
    CGPathAddLineToPoint(pathRef, nil, 300, 300);
    CGPathAddLineToPoint(pathRef, nil, 0, 300);
    CGPathAddLineToPoint(pathRef, nil, 150, 150);//与非闭合三角形的区别
    CGContextAddPath(context, pathRef);
    CGContextDrawPath(context, kCGPathFillStroke);
}

//任意弧形
-(void)drawMyArc {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];//内部填充颜色
    [COLOR2 setStroke];//边框颜色 CGContextStrokePath(context)
    CGContextSetLineWidth(context, 5.0);
    CGContextMoveToPoint(context, 100, 200);//弧形起始点
    //绘制弧形,最后的300,200是弧形终点,中间点200,100
    CGContextAddCurveToPoint(context, 200, 100, 200, 100, 300, 200);
    CGContextDrawPath(context, kCGPathFillStroke);
}

//波浪形,属于任意弧形
-(void)drawMyArc1 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];//内部填充颜色
    [COLOR2 setStroke];//边框颜色 CGContextStrokePath(context)
    CGContextSetLineWidth(context, 5.0);
    CGContextMoveToPoint(context, 100, 200);//弧形起始点
    //绘制弧形,最后的300,200是弧形终点
    CGContextAddCurveToPoint(context, 200, 100, 200, 300, 300, 200);
    CGContextDrawPath(context, kCGPathFillStroke);
}

//圆形
-(void)drawMyCircle {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];//内部填充颜色
    [COLOR2 setStroke];//边框颜色 CGContextStrokePath(context)
    //200,200圆心 半径150  0,M_PI*2->0到180度 最后一个参数:1顺时针0逆时针
    CGContextAddArc(context, 200, 200, 150, 0, M_PI*2, 1 );
    CGContextDrawPath(context, kCGPathFillStroke);
}

//弧形
-(void)drawMyCircle1 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];//内部填充颜色
    [COLOR2 setStroke];//边框颜色 CGContextStrokePath(context)
    CGContextSetLineWidth(context, 5.0);
    //200,200圆心 半径150  0,M_PI*2->0到360度 最后一个参数:1顺时针0逆时针
    CGContextAddArc(context, 200, 200, 150, 0, M_PI, 1 );
    CGContextClosePath(context);//闭合 
    CGContextDrawPath(context, kCGPathFillStroke);
}

//常见属性:1.颜色  2.线条粗细  3.线条两端  4.转折处连接  5.虚线
//线条两端(直线为例)
-(void)drawMyProperty1 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    //设置颜色
    [COLOR2 setStroke];
    CGContextSetLineWidth(context , 10.0);//当前线条宽度
    //kCGLineCapSquare端点是平的线,90度
    //kCGLineCapRound端点是有弧度的圆形
    CGContextSetLineCap(context, kCGLineCapRound );
    CGContextMoveToPoint(context, 100, 100);//绘制一个点
    CGContextAddLineToPoint(context, 300, 300);//另外一个点
    CGContextStrokePath(context);//渲染路径
}

//转折处属性设置(三角形为例,转折处由尖锐的形状设为弧形)
-(void)drawMyProperty2 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];//内部填充颜色
    [COLOR2 setStroke];//边框颜色 CGContextStrokePath(context)
    CGContextSetLineWidth(context, 5.0);
    CGContextSetLineJoin(context, kCGLineCapRound);
    CGMutablePathRef pathRef = CGPathCreateMutable();//创建一个多路径
    CGPathMoveToPoint(pathRef , nil, 150, 150);//在路径上绘制一个起点
    CGPathAddLineToPoint(pathRef, nil, 300, 300);
    CGPathAddLineToPoint(pathRef, nil, 0, 300);
    CGPathAddLineToPoint(pathRef, nil, 150, 150);
    CGContextAddPath(context, pathRef);
    CGContextDrawPath(context, kCGPathFillStroke);
}

//虚线
-(void)drawMyProperty3 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];
    [COLOR2 setStroke];
    CGContextSetLineWidth(context, 10.0);
    //虚线长度 3个代表三段
    CGFloat length[] = {10,20,10};
    //3:length的size 第二个参数:绘图过程中第一个点起始位置
    CGContextSetLineDash(context, 0, length, 3);
    CGContextMoveToPoint(context, 100, 0);
    CGContextAddLineToPoint(context, 100, 700);
    CGContextStrokePath(context);
    
}

//条形码
-(void)drawMyProperty4 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [COLOR1 setFill];
    [COLOR2 setStroke];
    CGContextSetLineWidth(context, 10.0);
    
    CGFloat length[] = {1,2,1,3,1,4,2,1};
    CGContextSetLineDash(context, 0, length, 8);
    CGContextMoveToPoint(context, 100, 0);
    CGContextAddLineToPoint(context, 100, 700);
    CGContextStrokePath(context);
    
}
@end
//
//  ViewController.m

#import "ViewController.h"
#import "Quartz.h"
@interface ViewController () {
    Quartz *quartz2d;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    quartz2d = [[Quartz alloc]initWithFrame:self.view.bounds];
    [self.view addSubview:quartz2d];
    [quartz2d setNeedsDisplay];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
虚线效果图.jpeg
条形码效果图.jpeg

三.图表绘制

//
//  Quartz2D.h

#import <UIKit/UIKit.h>
#define COLOR1 [UIColor colorWithRed:0.30 green:0.73 blue:0.49 alpha:1.0]
#define COLOR2 [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]
#define COLOR3 [UIColor colorWithRed:0.65 green:0.43 blue:0.87 alpha:1.0]
#define COLOR4 [UIColor colorWithRed:0.28 green:0.77 blue:0.30 alpha:1.0]
#define COLOR5 [UIColor colorWithRed:0.97 green:0.55 blue:0.62 alpha:1.0]

@interface Quartz2D : UIView
-(void)drawXY:(CGContextRef )context;
@end
//
//  Quartz2D.m
#import "Quartz2D.h"

@implementation Quartz2D


- (void)drawRect:(CGRect)rect {
    // Drawing code
    [self drawMyLine];
}

//折线图 1.坐标 2.内容
-(void)drawMyLine {
    CGContextRef context = UIGraphicsGetCurrentContext();
    //2.内容:直线
    [COLOR1 setStroke];
    CGContextSetLineWidth(context, 10.0);
    //1.坐标
    //图形的上下文栈 1.save 入栈 2.Restore 出栈
    CGContextSaveGState(context);
    [COLOR2 setStroke];
    CGContextSetLineWidth(context, 1.0);
    [self drawXY:context];
    CGContextRestoreGState(context);
    
    //直线
    CGContextMoveToPoint(context, 70, 260);
    CGContextAddLineToPoint(context, 100, 50);
    CGContextAddLineToPoint(context, 200, 240);
    CGContextAddLineToPoint(context, 250, 170);
    CGContextAddLineToPoint(context, 350, 210);
    CGContextStrokePath(context);
}

-(void)drawXY:(CGContextRef )context {
    CGContextMoveToPoint(context, 50, 350);
    CGContextAddLineToPoint(context, 410, 350);
    CGContextAddLineToPoint(context, 400, 345);//箭头
    CGContextMoveToPoint(context, 410, 350);
    CGContextAddLineToPoint(context, 400, 355);//箭头
    
    CGContextMoveToPoint(context, 50, 350);
    CGContextAddLineToPoint(context, 50, 20);
    CGContextAddLineToPoint(context, 45, 30);//箭头
    CGContextMoveToPoint(context, 50, 20);
    CGContextAddLineToPoint(context, 55, 30);//箭头
    
    CGContextStrokePath(context);
    
}

//柱状图:width+line设置直线,加粗
-(void)drawMyBarChart1 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    //2.内容:直线
    [COLOR1 setStroke];
    CGContextSetLineWidth(context, 25.0);
    //1.坐标
    //图形的上下文栈 1.save 入栈 2.Restore 出栈
    CGContextSaveGState(context);
    [COLOR2 setStroke];
    CGContextSetLineWidth(context, 1.0);
    [self drawXY:context];
    CGContextRestoreGState(context);
    
    CGContextMoveToPoint(context, 90, 320);
    CGContextAddLineToPoint(context, 90, 50);
    
    CGContextMoveToPoint(context, 160, 320);
    CGContextAddLineToPoint(context, 160, 50);
    
    CGContextMoveToPoint(context, 230, 320);
    CGContextAddLineToPoint(context, 230, 240);
    
    CGContextMoveToPoint(context, 300, 320);
    CGContextAddLineToPoint(context, 300, 170);
    
    CGContextMoveToPoint(context, 370, 320);
    CGContextAddLineToPoint(context, 370, 210);
    
    CGContextStrokePath(context);
}

//空心柱状图:设置矩形
-(void)drawMyBarChart2 {
    CGContextRef context = UIGraphicsGetCurrentContext();
    //2.内容:直线
    [COLOR1 setStroke];
    CGContextSetLineWidth(context, 3.0);
    //1.坐标
    //图形的上下文栈 1.save 入栈 2.Restore 出栈
    CGContextSaveGState(context);
    [COLOR2 setStroke];
    CGContextSetLineWidth(context, 1.0);
    [self drawXY:context];
    CGContextRestoreGState(context);
    
    CGContextAddRect(context, CGRectMake(80, 250, 40, 70));
    CGContextAddRect(context, CGRectMake(150, 250, 40, 70));
    CGContextAddRect(context, CGRectMake(220, 80, 40, 240));
    CGContextAddRect(context, CGRectMake(290, 140, 40, 180));
    CGContextAddRect(context, CGRectMake(360, 40, 40, 280));
    
    CGContextDrawPath(context, kCGPathStroke);
}

//饼状图
-(void)drawMyPie {
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextSaveGState(context);
    [COLOR2 setStroke];
    CGContextSetLineWidth(context, 1.0);
    CGContextMoveToPoint(context, 200, 200);//圆心
    CGContextAddArc(context, 200, 200, 150, 0, M_PI*2, 0);//绘制圆
    CGContextDrawPath(context, kCGPathStroke);
    CGContextRestoreGState(context);
    //饼状图part1
    CGContextSaveGState(context);
    [COLOR2 setFill];
    CGContextSetLineWidth(context, 1.0);
    CGContextMoveToPoint(context, 200, 200);
    CGContextAddArc(context, 200, 200, 150, 0, M_PI*2*0.6, 0);
    CGContextDrawPath(context, kCGPathFill);
    CGContextRestoreGState(context);
    
    //饼状图part2
    CGContextSaveGState(context);
    [COLOR3 setFill];
    CGContextSetLineWidth(context, 1.0);
    CGContextMoveToPoint(context, 200, 200);
    CGContextAddArc(context, 200, 200, 150, M_PI*2*0.6, M_PI*2*0.8, 0);
    CGContextDrawPath(context, kCGPathFill);
    CGContextRestoreGState(context);
    
    //饼状图part3
    CGContextSaveGState(context);
    [COLOR4 setFill];
    CGContextSetLineWidth(context, 1.0);
    CGContextMoveToPoint(context, 200, 200);
    CGContextAddArc(context, 200, 200, 150, M_PI*2*0.8, M_PI*2*0.95, 0);
    CGContextDrawPath(context, kCGPathFill);
    CGContextRestoreGState(context);
    
    //饼状图part4
    CGContextSaveGState(context);
    [COLOR5 setFill];
    CGContextSetLineWidth(context, 1.0);
    CGContextMoveToPoint(context, 200, 200);
    CGContextAddArc(context, 200, 200, 150, M_PI*2*0.95, M_PI*2, 0);
    CGContextDrawPath(context, kCGPathFill);
    CGContextRestoreGState(context);
    
    //比例
    CGContextSaveGState(context);
    [COLOR3 setStroke];
    CGContextSetLineWidth(context, 1.0);
    CGContextMoveToPoint(context, 200, 320);
    CGContextAddLineToPoint(context, 260, 370);
    CGContextAddLineToPoint(context, 330, 370);
    CGContextDrawPath(context, kCGPathStroke);
    CGContextRestoreGState(context);
    
    //百分比:1.文字渲染(还没讲) 2.UILabel
    UILabel *lab = [[UILabel alloc]initWithFrame:CGRectMake(330, 357, 50, 20)];
    lab.text = @"60.0%";
    lab.textColor = COLOR3;
    [self addSubview:lab];//注意不要增加到self.view上
}
@end
//
//  ViewController.m


#import "ViewController.h"
#import "Quartz2D.h"
@interface ViewController () {
    Quartz2D *quartz2dView;
}

@end


@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    quartz2dView = [[Quartz2D alloc]initWithFrame:self.view.bounds];
    [self.view addSubview:quartz2dView];
    [quartz2dView setNeedsDisplay];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
饼状图效果图.jpeg

四.drawRect认识

  1. UIView drawRect方法
  2. 让用户对于当前view重新绘制
  3. 调用:不在init方法调用,在设置当前frame或改变大小时被触发,在主动调用setNeedsDisplay时也会被触发

五.下载进度条的实现

//
//  Quartz.h

#import <UIKit/UIKit.h>
#define COLOR1 [UIColor colorWithRed:0.30 green:0.73 blue:0.49 alpha:1.0]
#define COLOR2 [UIColor colorWithRed:0.65 green:0.43 blue:0.87 alpha:1.0]
@interface Quartz : UIView
@property(nonatomic,assign)int percent;
@end
//
//  Quartz.m

#import "Quartz.h"

@implementation Quartz
-(instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.percent = 0;
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    if (self.percent != 0) {
        CGContextRef context = UIGraphicsGetCurrentContext();
        [COLOR1 setStroke];
        CGContextSetLineCap(context, kCGLineCapRound);
        CGContextSetLineWidth(context, 15.0);
        CGContextMoveToPoint(context, 25, 208);
        CGContextAddLineToPoint(context, 25+(self.percent/100.0)*(414-50), 208);//414是iPhone6s plus屏幕的宽度
        CGContextStrokePath(context);
    }
}


@end
//
//  ViewController.m

#import "ViewController.h"
#import "Quartz.h"
@interface ViewController () {
    Quartz *quartzView;
    int i;//描述当前百分比
    UILabel *lab;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blackColor];
    
    UIView *view = [[UIView alloc]initWithFrame:CGRectMake(20, 200, 414-40, 15)];
    view.backgroundColor = COLOR2;
    view.layer.cornerRadius = 7.0;
    [self.view addSubview:view];
    
    lab = [[UILabel alloc]initWithFrame:CGRectMake(414-120, 170, 100, 20)];
    lab.text = @"0.0%";
    lab.textColor = [UIColor whiteColor];
    lab.textAlignment = NSTextAlignmentRight;
    [self.view addSubview:lab];
    
    quartzView = [[Quartz alloc]initWithFrame:self.view.bounds];
    quartzView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:quartzView];
    
    i = 0;
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(loadRefresh) userInfo:nil repeats:true];
    
}

-(void)loadRefresh {
    if (i<100) {
        i++;
    }else {
        i = 100;
    }
    quartzView.percent = i;
    [quartzView setNeedsDisplay];
    lab.text = [NSString stringWithFormat:@"%d%@",i,@"%"];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
下载进度条效果图.jpeg

六.图形上下文栈

  1. 图形上下文栈概念
  2. 图片绘制
  3. 图片裁剪
  4. 文字log绘制
  5. 图片log
  6. 图片几何变换
  7. 屏幕截屏
//
//  ViewController.m

#import "ViewController.h"
#import "Quartz.h"
@interface ViewController () {
    Quartz *quartzView;
    
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    quartzView = [[Quartz alloc]initWithFrame:self.view.bounds];
    [self.view addSubview:quartzView];
    [quartzView setNeedsDisplay];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
//
//  Quartz.h


#import <UIKit/UIKit.h>
#define COLOR1 [UIColor colorWithRed:0.30 green:0.73 blue:0.49 alpha:1.0]
#define COLOR2 [UIColor colorWithRed:0.65 green:0.43 blue:0.87 alpha:1.0]
@interface Quartz : UIView

@end
//
//  Quartz.m


#import "Quartz.h"

@implementation Quartz


- (void)drawRect:(CGRect)rect {
//    [self drawMyLine];
//    [self drawMyImage];
//    [self drawMyImageClip];
//    [self drawMyTitle];
//    [self drawMyImage2];
//    [self drawMyImage3];

}
//图层上下文栈
-(void)drawMyLine {
    CGContextRef context = UIGraphicsGetCurrentContext();
    //在图层上下文栈之间,设置的属性只对该栈内起作用
    CGContextSaveGState(context);//入栈
    [COLOR1 setStroke];
    CGContextSetLineWidth(context, 10.0);
    CGContextMoveToPoint(context, 100, 20);
    CGContextAddLineToPoint(context, 100, 400);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);//出栈
    
    CGContextSaveGState(context);//入栈
    [COLOR2 setStroke];
    CGContextSetLineWidth(context, 2.0);
    CGContextMoveToPoint(context, 200, 20);
    CGContextAddLineToPoint(context, 200, 400);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);//出栈
    
    CGContextSaveGState(context);//入栈
    [COLOR1 setStroke];
    CGContextSetLineWidth(context, 6.0);
    CGContextMoveToPoint(context, 300, 20);
    CGContextAddLineToPoint(context, 100, 400);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);//出栈
}
//图片绘制
-(void)drawMyImage {
    UIImage *image = [UIImage imageNamed:@"3.jpg"];
//    [image drawAtPoint:CGPointMake(100, 100)];//把图片(左上角)绘制到某一个点
//    [image drawInRect:CGRectMake(100, 100, 300, 600)];//把图片填充到某一区域
    
    [image drawAsPatternInRect:CGRectMake(100, 100, 300, 600)];//快速拷贝到充满整个区域
}

//图片裁剪:裁剪成圆形
-(void)drawMyImageClip {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextAddEllipseInRect(context, CGRectMake(150, 150, 60, 60));//创建一个60*60内部是圆形的矩形
    CGContextClip(context);//裁剪
    CGContextFillPath(context);
    UIImage *image = [UIImage imageNamed:@"3.jpg"];
    [image drawAtPoint:CGPointMake(150, 150)];
    CGContextRestoreGState(context);
}

//文字log绘制
-(void)drawMyTitle {
    NSString *str = @"balabala";
    UIImage *image = [UIImage imageNamed:@"3.jpg"];
    [image drawAtPoint:CGPointMake(100, 100)];
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle]mutableCopy];
    paragraphStyle.lineBreakMode = NSLineBreakByClipping;//截断方式
    //3个属性:文字大小 文字截断方式 颜色
    NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:10.0],NSParagraphStyleAttributeName:paragraphStyle,NSForegroundColorAttributeName:[UIColor greenColor]};
    [str drawInRect:CGRectMake(100, 100, 100, 10) withAttributes:dic];
}

//图片log绘制:呈现的效果是图片的左上角有一张小的图片
-(void)drawMyImage2 {
    UIImage *image = [UIImage imageNamed:@"3.jpg"];
    [image drawAtPoint:CGPointMake(100, 100)];
    [image drawAsPatternInRect:CGRectMake(100, 100, 30, 20)];
}

//图片几何变换:不是将图片整个旋转,而是将图片里每一个像素点进行旋转
//后数据 算法优化 -> 特效相机  会用到 很重要
-(void)drawMyImage3 {
    UIImage *image = [UIImage imageNamed:@"3.jpg"];
    size_t width = 100;
    size_t height = 63;
    //每个像素:R+G+B+alpha 每个元素占一个字节,所以*4
    //RGB(对一种颜色进行编码的方法,红、绿、蓝) alpha
    size_t bytePerRow = width*4;
    CGImageAlphaInfo alphaInfo = kCGImageAlphaPremultipliedFirst;
    //参数4:每个元素数据位数,1字节=8bits
    CGContextRef bitmapContext = CGBitmapContextCreate(NULL, width, height , 8, bytePerRow, CGColorSpaceCreateDeviceRGB(),kCGBitmapByteOrderDefault| alphaInfo);
    //渲染
    CGContextDrawImage(bitmapContext, CGRectMake(0, 0, width, height), image.CGImage);
    UInt8 *data = (UInt8 *)CGBitmapContextGetData(bitmapContext);
    //vImage_Buffer是图像的缓存
    vImage_Buffer src = {data,height,width,bytePerRow};//源
    vImage_Buffer dest = {data,height,width,bytePerRow};//目标
    Pixel_8888 bgColor = {0,0,0,0};
    //&符号是取地址符号,准确的获取到存储数据的位置。
    vImageRotate_ARGB8888(&src, &dest, NULL, M_PI, bgColor, kvImageBackgroundColorFill);
    
    CGImageRef rotateImageRef = CGBitmapContextCreateImage(bitmapContext);
    UIImage *imageNew = [UIImage imageWithCGImage:rotateImageRef scale:0.5  orientation:image.imageOrientation];//scale:缩放 imageOrientation:图片原始方向
    [imageNew drawAtPoint:CGPointMake(100, 100)];
    
}
@end

屏幕截屏
这个功能需要添加权限,因为需要访问相册
Privacy - Photo Library Usage Description
Privacy - Photo Library Additions Usage Description
一定要添加文字,不可以为空

权限.jpeg
/*  这是一个UIView的分类,截屏功能是对当前的view进行操作, 如果我们把实现代码
写在UIView的分类中,就直接可以通过self.view调用方法名来获取截屏后的图片*/
//  UIView+ScreenView.h


#import <UIKit/UIKit.h>

@interface UIView (ScreenView)
-(UIImage*)imageScreenShot;
@end

//
//  UIView+ScreenView.m

#import "UIView+ScreenView.h"

@implementation UIView (ScreenView)
-(UIImage*)imageScreenShot {
    UIGraphicsBeginImageContext(self.frame.size);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *imageNew = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return imageNew;
}
@end
//
//  ViewController.m


#import "ViewController.h"
#import "UIView+ScreenView.h"
@interface ViewController () {
     
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    UIImage *image = [self.view imageScreenShot];
    //保存到本地相册
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

七.股市K线的实现

红色代表涨了,绿色代表跌了
白色线:MA5,最近5天收盘价的平均值
黄色线:MA10或MA20


名词解释

data.txt 1.当天的时间 2.开盘价 3.收盘价 4.当天最高价 5.当天最低价 6.成交量

150821 10.95 9.59 11.37 9.52 3040949
150828 9.30 8.78 9.30 7.65 3307582
150902 8.74 9.10 9.25 8.26 1975752
150911 9.00 9.08 9.35 8.27 2154360
150918 9.08 8.44 9.08 7.98 1670966
150925 8.38 8.32 8.99 8.27 1326006
150930 8.27 8.21 8.39 8.12 278988
151009 8.49 8.49 8.56 8.36 575752
151016 8.54 9.06 9.10 8.52 1843725
151023 9.18 9.64 9.79 8.70 2815237
151030 9.82 9.45 9.87 9.12 2154922
151106 9.25 9.74 9.94 9.03 2084890
151113 9.70 9.35 10.05 9.33 1827356
151120 9.11 9.65 10.07 9.11 1937990
151127 9.64 9.14 9.84 9.09 1444027
151204 9.20 12.55 13.00 9.07 6999919
151211 12.50 11.43 12.78 11.15 7759820
151218 11.59 12.39 13.48 11.34 5905508
151225 12.22 12.79 14.90 12.21 8191994
151231 12.76 11.53 12.84 11.52 3759800
160108 11.50 10.02 11.55 9.33 4023011
160115 9.80 9.78 10.37 9.01 4403801
160122 9.60 9.44 10.45 9.16 3170055
160129 9.46 8.61 9.60 8.01 2335738
160205 8.55 9.00 9.29 8.45 1996550
160219 8.69 9.00 9.44 8.64 1433428
160226 9.15 8.51 9.43 8.34 1741154
160304 8.66 9.64 10.16 8.53 4128644
160311 9.90 8.88 9.90 8.80 1314886
160318 9.00 9.36 9.44 8.86 1375466
160325 9.50 9.50 9.70 9.23 1596092
160401 9.55 9.25 9.55 8.98 1104512
160408 9.25 9.17 9.47 9.08 841764
160415 9.21 9.44 9.50 9.11 1089570
160422 9.44 9.09 9.44 8.86 763694
160429 9.09 9.03 9.13 8.86 495156
160506 9.05 9.53 9.77 8.99 1554858
160513 9.43 9.84 10.70 9.21 2716045
160520 9.85 10.02 10.31 9.58 1693427
160527 9.97 9.63 10.06 9.40 797109
160603 9.65 10.16 10.24 9.56 1150485
160608 10.30 9.91 10.32 9.87 506659
160617 9.83 9.57 9.83 9.41 886345
160624 9.59 9.31 9.70 9.15 697778
160701 9.27 9.77 9.85 9.24 980400
160708 9.73 9.75 10.11 9.48 1569575
160715 9.73 10.04 10.31 9.62 1385489
160722 9.98 9.74 10.03 9.66 781721
160729 9.73 10.40 10.85 9.68 1548811
160805 10.35 10.98 11.56 10.02 1693267
160812 10.93 11.74 11.74 10.54 2180460
160819 12.11 13.70 14.43 11.94 7758308
160826 13.60 11.90 14.14 11.81 4959598
160902 11.94 11.66 12.78 11.53 3379144
160909 11.71 11.46 11.90 11.45 1543169
160914 11.20 11.13 11.36 11.05 767659
160923 11.20 11.82 12.45 11.11 2440352
//
//  StockClass.h

#import <Foundation/Foundation.h>

@interface StockClass : NSObject
@property(nonatomic,copy) NSString *time;//股票交易时间
@property(nonatomic,assign) float beginPrice;
@property(nonatomic,assign) float endPrice;
@property(nonatomic,assign) float maxPrice;
@property(nonatomic,assign) float minPrice;
@property(nonatomic,assign) int tradeVolume;//成交额 

@end
//
//  QuartzChart.h

#import <UIKit/UIKit.h>
#import "StockClass.h"
@interface QuartzChart : UIView
-(instancetype)initWithFrame:(CGRect)frame stockData:(NSMutableArray *) mstockData;
@end
//
//  QuartzChart.m

#import "QuartzChart.h"

#define COLOR1 [UIColor colorWithRed:220/255.0 green:20/255.0 blue:60/255.0 alpha:1.0]
#define COLOR2 [UIColor colorWithRed:34/255.0 green:139/255.0 blue:34/255.0 alpha:1.0]
#define BEGIN_Y 300
@interface QuartzChart() {
    NSMutableArray *stockData;
}

@end
@implementation QuartzChart
-(instancetype)initWithFrame:(CGRect)frame stockData:(NSMutableArray *) mstockData {
    self = [super initWithFrame:frame];
    if (self) {
        stockData = mstockData;
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    [self drawMyRect];
    [self drawMyLine];
}
//柱状图
-(void)drawMyRect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 1.0);
    for (int i = 17; i<stockData.count; i++ ) {
        StockClass *item = [stockData objectAtIndex:i];
        float beginPrice = item.beginPrice;
        float endPrice = item.endPrice;
        [COLOR2 setStroke];
        [COLOR2 setFill];
        if (beginPrice > endPrice) {
            //下跌
            CGContextAddRect(context, [self getCurrentRect:i-17 beginPrice:beginPrice endPrice:endPrice]);
            CGContextDrawPath(context, kCGPathFillStroke);
        }else{
            //上涨
            CGContextSaveGState(context);
            [COLOR1 setStroke];
            [COLOR1 setFill];
            CGContextAddRect(context, [self getCurrentRect:i-17 beginPrice:beginPrice endPrice:endPrice] );
            CGContextDrawPath(context, kCGPathFillStroke);
            CGContextRestoreGState(context);
        }
    }
}

-(CGRect)getCurrentRect:(int)i beginPrice:(float)beginPrice endPrice:(float)endPrice {
    CGFloat x = i*414.0/40;
    CGFloat y = 0;
    CGFloat w = 414.0/40-4;
    CGFloat h = fabsf(beginPrice - endPrice);//绝对值
    if (beginPrice>endPrice) {
        y=300-beginPrice;
    }else {
        y = 300-endPrice;
    }
    return CGRectMake(x, y, w, h);
}

//上下引线
-(void)drawMyLine {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 1.0);
    for (int i = 17; i<stockData.count; i++ ) {
        StockClass *item = [stockData objectAtIndex:i];
        float beginPrice = item.beginPrice;
        float endPrice = item.endPrice;
        float maxPrice = item.maxPrice;
        float minPrice = item.minPrice;
        [COLOR2 setStroke];
        [COLOR2 setFill];
        if (beginPrice > endPrice) {
            //下跌
            CGPoint maxBeginPoint = [self getMaxBeginPoint:i-17 maxPrice:maxPrice];
            CGContextMoveToPoint(context, maxBeginPoint.x, maxBeginPoint.y);
            CGPoint maxEndPoint = CGPointMake(maxBeginPoint.x, BEGIN_Y-endPrice);
            CGContextAddLineToPoint(context, maxEndPoint.x, maxEndPoint.y);
            
            CGPoint minBeginPoint = [self getMinBeginPoint:i-17 lowPrice:beginPrice];
            CGContextMoveToPoint(context, minBeginPoint.x, minBeginPoint.y);
            CGPoint minEndPoint = CGPointMake(minBeginPoint.x, BEGIN_Y-minPrice);
            CGContextAddLineToPoint(context, minEndPoint.x, minEndPoint.y);
            
            CGContextDrawPath(context, kCGPathFillStroke);
            
        }else {
            //上涨
            CGContextSaveGState(context);
            [COLOR1 setStroke];
            [COLOR1 setFill];
            
            CGPoint maxBeginPoint = [self getMaxBeginPoint:i-17 maxPrice:maxPrice];
            CGContextMoveToPoint(context, maxBeginPoint.x, maxBeginPoint.y);
            CGPoint maxEndPoint = CGPointMake(maxBeginPoint.x, BEGIN_Y-beginPrice);;
            CGContextAddLineToPoint(context, maxEndPoint.x, maxEndPoint.y);
            
            CGPoint minBeginPoint = [self getMinBeginPoint:i-17 lowPrice:endPrice];
            CGContextMoveToPoint(context, minBeginPoint.x, minBeginPoint.y);
            CGPoint minEndPoint = CGPointMake(minBeginPoint.x, BEGIN_Y-minPrice);
            CGContextAddLineToPoint(context, minEndPoint.x, minEndPoint.y);
            
            CGContextDrawPath(context, kCGPathFillStroke);
            CGContextRestoreGState(context);
        }
    }
}

-(CGPoint)getMaxBeginPoint:(int)i maxPrice:(float)maxPrice {
    CGFloat w = 414.0/40-4 ;
    CGFloat x = i*414.0/40+w/2;
    CGFloat y = BEGIN_Y - maxPrice;
    return CGPointMake(x, y);
}

-(CGPoint)getMinBeginPoint:(int)i lowPrice:(float)lowPrice {
    CGFloat w = 414.0/40-4 ;
    CGFloat x = i*414.0/40+w/2;
    CGFloat y = BEGIN_Y - lowPrice;
    return CGPointMake(x, y);
}


@end
//
//  ViewController.m
//  1.数据处理 2.K线图绘制
//  1.1数据加载 1.2数据解析 1.3数据归一化处理
#import "ViewController.h"
#import "StockClass.h"
#import "QuartzChart.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSMutableArray *array1 = [self loadStockData];
    NSMutableArray *array2 = [self parseStockData:array1];
    NSMutableArray *newStock = [self normalizingData:array2];
    
    QuartzChart *quartz = [[QuartzChart alloc]initWithFrame: self.view.frame stockData:newStock];
    [self.view addSubview:quartz];
    [quartz setNeedsDisplay];
}
//数据加载
-(NSMutableArray *)loadStockData {
    NSString *filePath = [[NSBundle mainBundle]pathForResource:@"data" ofType:@"txt"];
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    NSString *stockListStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
    //将每行数据放入数组
    NSMutableArray *array = [[NSMutableArray alloc] initWithArray:[stockListStr componentsSeparatedByString:@"\n"]];
    return array;
}

//数据解析
-(NSMutableArray *)parseStockData:(NSMutableArray *)stockData {
    [stockData removeLastObject];
    NSMutableArray *stockArray = [[NSMutableArray alloc]init];
    for (int i = 0; i<stockData.count;i++) {
        NSString *str = [stockData objectAtIndex:i];
        NSMutableArray *oneStock = [[NSMutableArray alloc]initWithArray:[str componentsSeparatedByString:@" "]];
        NSString *time = [oneStock objectAtIndex:0];
        NSString *beginPrice = [oneStock objectAtIndex:1];
        NSString *endPrice = [oneStock objectAtIndex:2];
        NSString *maxPrice = [oneStock objectAtIndex:3];
        NSString *minPrice = [oneStock objectAtIndex:4];
        NSString *trade = [oneStock objectAtIndex:5];
        
        StockClass *oneStk = [[StockClass alloc]init];
        oneStk.time = time;
        oneStk.beginPrice = beginPrice.floatValue;
        oneStk.endPrice = endPrice.floatValue;
        oneStk.maxPrice = maxPrice.floatValue;
        oneStk.minPrice = minPrice.floatValue;
        oneStk.tradeVolume = trade.intValue;
        
        [stockArray addObject:oneStk];
    }
    return stockArray;
}

//数据归一化处理 1.0-1 2.0-300
-(NSMutableArray *)normalizingData:(NSMutableArray *)stockData {
    float maxPriceAll = 0;
    float minPriceAll = 10000;
    float maxTradeAll = 0;
    float minTradeAll = 10000000;
    for (StockClass *item in stockData) {
        float maxPrice = item.maxPrice;
        float minPrice = item.minPrice;
        int trade = item.tradeVolume;
        if (maxPriceAll < maxPrice) {
            maxPriceAll = maxPrice;
        }
        if (minPriceAll > minPrice) {
            minPriceAll = minPrice;
        }
        if (maxTradeAll < trade) {
            maxTradeAll = trade;
        }
        if (minTradeAll > trade) {
            minTradeAll = trade;
        }
    }
    NSMutableArray *newStock = [[NSMutableArray alloc]init];
    for (StockClass *item in stockData) {
        item.beginPrice = (item.beginPrice - minPriceAll)*300/(maxPriceAll - minPriceAll);//先转换为0到1之间,再转换为0到300之间
        item.endPrice = (item.endPrice - minPriceAll)*300/(maxPriceAll - minPriceAll);
        item.maxPrice = (item.maxPrice - minPriceAll)*300/(maxPriceAll - minPriceAll);
        item.minPrice = (item.minPrice - minPriceAll)*300/(maxPriceAll - minPriceAll);
        item.tradeVolume = (item.tradeVolume - minTradeAll)*300/(maxTradeAll - minTradeAll);
        [newStock addObject:item];
    }
    return newStock;
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
K线图效果图.jpeg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,302评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,232评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,337评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,977评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,920评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,194评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,638评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,319评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,455评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,379评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,426评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,106评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,696评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,786评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,996评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,467评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,043评论 2 341

推荐阅读更多精彩内容