天天看点

ios--Quartz2绘图

1.什么是Quartz2D:

是一个二维绘图引擎,同时支持iOS和Mac OS系统(跨平台,C语言写的),包含在

core graphICS 框架中,

2.Quartz2D能干什么?

绘制图形:线条,三角形,矩形,圆,弧等

绘制文字

绘制/生成图片

读取生成PDF

截图/裁剪图片

自定义UI控件

3.注意:

Quartz2D是苹果官方的二维绘图引擎,同时支持iOS和Mac OS系统,

Cocos2D(Cocos2D-X,Cocos2D-iphone,Cocos2D-html等)是一个第三方开源的2D游戏框架,做2D游戏的还有Spite Kit,一般3D游戏用unity3D

4.Quartz2D须知:

Quartz2D的API是C语言写的

Quartz2D的API来自Core Graphic框架

数据类型和函数基本都以CG作为前缀

CG类和ontextRef

CGPathRef

CGContextStrokePath(ctx)

... 

5.Quartz2D绘图主要步骤:

1.获取[图形上下文]对象

2.向[图形上下文] 对象中添加[路径]

3.渲染(把[图形上下文]中的图形绘制到对应的设备上)

4.图形上下文CGContextRef:

图形上下文中主要包含如下信息:

1.绘图路径(各种各样的图形)

2.绘图状态(颜色,线宽,样式,旋转,缩放,平移,图片裁剪区域)

3.输出目标(绘制到什么地方去,UIView,图片,PDF,打印机等)

(输出目标可以是PDF文件,bitmap或者显示器的窗口上)

要绘制的图形 -保存->图形上下文-显示->输出目标

相同的一套绘图序列,制定不同的Graphics Context,就可以将相同的图像绘制到不同目标上.

图形上下文对象:

graphICS context:

Bitmap graphICS context

PDF graphICS context

Window  graphICS context

layer graphICS context(UIView控件)

Printer graphICS context

使用Quartz2D绘图:

方式1:直接条用Quartz2D的API进行绘制

代码量稍大

功能全面

步骤:

获取绘图上下文

把图形绘制到图形上下文上

把图形上下文渲染到相应设备上

方式2:调用UIKit 框架封装好的API进行绘图

代码相对简单

只对部分Quartz2D API做了封装

对于没有封装的功能只能调用Quartz2D 原生的API

比如:画图片,文字到控件上(UIKit已经封装好了)

 6.绘图的方式:

  1.使用C语言:

#import "myUIView.h"

@implementation myUIView

- (void)drawRect:(CGRect)rect{

   //1.获取上下文

   CGContextRef ctx = UIGraphicsGetCurrentContext();

   //2.拼接路径,同时把路径添加到上下文中

   CGContextMoveToPoint(ctx, 10, 100);//移动到点

   CGContextAddLineToPoint(ctx, 20, 100);//画线到点

   //3.渲染

   CGContextStrokePath(ctx);

}

2.使用C语言+oc语言或swift:

#import "myUIView.h"

@implementation myUIView

- (instancetype)initWithFrame:(CGRect)frame{

   self = [super initWithFrame:frame];

   if(self){

       self.backgroundColor = [UIColor blueColor];

       return self;

   }

   return nil;

}

- (void)drawRect:(CGRect)rect{

   //1.获取上下文

   CGContextRef ctx = UIGraphicsGetCurrentContext();

   //2.拼接路径

   UIBezierPath *path = [[UIBezierPath alloc] init];

   [path moveToPoint:CGPointMake(0, 0)];

   [path addLineToPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height)];

   [path addLineToPoint:CGPointMake(self.bounds.size.width, 0)];

   [path addLineToPoint:CGPointMake(0, self.bounds.size.height)];

   //3.把路径添加到上下文中

   CGContextAddPath(ctx, path.CGPath);

   //4.渲染

   CGContextStrokePath(ctx);

}

@end

3.使用oc语言或swift语言:

- (void)drawRect:(CGRect)rect{

   //1.创建路径

   UIBezierPath *path = [[UIBezierPath alloc] init];

   [path moveToPoint:CGPointMake(0, 0)];\

   [path addLineToPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height)];

   //2.渲染

   [path stroke];

}

7.drawRect:

1.绘图代码为什么要写在drawRect方法中?

因为在这个方法中可以获取到正确的上下文

2.drawRect的参数(CGRect)rect含义:

rect是当前view的Bounds(在窗口中得位置)

3.drawRect方法什么时候调用:

1.当这个view第一次显示的时候

2.重绘(相当于TableView的刷新)的时候会调用

4.如何进行重绘:

需要调用需要重绘view的 setNeedsDisplay方法

需要调用需要重绘view的 setNeedsDisplayInRect方法,Rect 制定刷新的区域

5.为什么不能手动调用drawRect方法:

因为要获取到正确的绘图上下文,手动调用的话,系统可能还没创建好上下文

8.绘图练习:

1.绘制线段:

- (void)drawRect:(CGRect)rect{

   //1.创建路径

   UIBezierPath *path = [[UIBezierPath alloc] init];

   [path moveToPoint:CGPointMake(10, 10)];

   [path addLineToPoint:CGPointMake(50, 50)];

   UIBezierPath *path1 = [[UIBezierPath alloc] init];

   [path1 moveToPoint:CGPointMake(30, 10)];

   [path1 addLineToPoint:CGPointMake(70, 80)];

   //2.渲染

   [path stroke];

   [path1 stroke];

}

2.画矩形:

- (void)drawRect:(CGRect)rect{

   //1.创建路径

   UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(10, 10, 50, 50)];

   //2.渲染

   [path stroke];

}

3.画圆角矩形:

- (void)drawRect:(CGRect)rect{

   //1.创建路径

   UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(10, 10, 50, 50) cornerRadius:15];

   //2.渲染

   [path stroke];

}

4.画椭圆(当宽度和高度一样的时候是圆):

- (void)drawRect:(CGRect)rect{

   //1.创建路径

   UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 30, 40)];

   //2.渲染

   [path stroke];

}

5.画弧:

- (void)drawRect:(CGRect)rect{

   //1.创建路径

   UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 50) radius:20 startAngle:M_PI / 3 endAngle:M_PI / 2 clockwise:YES];//参数:圆心,半径,开始位置,结束位置,是否顺时针

   //2.渲染

   [path stroke];

}

6.画圆环:

- (void)drawRect:(CGRect)rect{

   //1.创建路径

   UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 50) radius:20 startAngle:0 endAngle:M_PI * 2 clockwise:YES];

   UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 50) radius:10 startAngle:0 endAngle:M_PI * 2 clockwise:YES];

   //2.渲染

   [path1 stroke];

   [path stroke];

}

9.绘图的样式:

1.设置线宽:

C语言:

- (void)drawRect:(CGRect)rect{

   //1.创建路径

   CGContextRef ctx = UIGraphicsGetCurrentContext();

   CGContextMoveToPoint( ctx, 10, 10);

   CGContextAddLineToPoint(ctx, 50, 50);

   CGContextAddLineToPoint(ctx, 20, 10);

   //设置线条宽度

   CGContextSetLineJoin(ctx, kCGLineJoinBevel);

   CGContextSetLineCap(ctx, kCGLineCapButt);

   CGContextSetLineWidth(ctx, 10);

   //设置颜色

   CGContextSetRGBStrokeColor(ctx, 0, 1, 1, 1);

   CGContextStrokePath(ctx);

}

oc语言或swift:

- (void)drawRect:(CGRect)rect{

   UIBezierPath *path = [[UIBezierPath alloc] init];

   [path moveToPoint:CGPointMake(10, 20)];

   [path addLineToPoint:CGPointMake(50, 60)];

   [path addLineToPoint:CGPointMake(10, 60)];

    [path closePath];//关闭路径

   [path setLineWidth:5];//设置线宽度

   [path setLineCapStyle:kCGLineCapButt];//设置开始和结尾的样式

   [path setLineJoinStyle:kCGLineJoinBevel];//设置连接处的 样式

   //设置颜色

    [[UIColor redColor] setStroke];

   [path stroke];

}

- (void)drawRect:(CGRect)rect{

   UIBezierPath *path = [[UIBezierPath alloc] init];

   [path moveToPoint:CGPointMake(10, 20)];

   [path addLineToPoint:CGPointMake(50, 60)];

   [path addLineToPoint:CGPointMake(10, 60)];

//    [path addLineToPoint:CGPointMake(10, 20)];

   [path closePath];//关闭路径

   [path setLineWidth:2];//设置线宽度

   [path setLineCapStyle:kCGLineCapButt];//设置开始和结尾的样式

   [path setLineJoinStyle:kCGLineJoinBevel];//设置连接处的 样式

   //设置颜色线条

   [[UIColor redColor] setStroke];

   //设置填充

   //    [path fill];

   [[UIColor yellowColor] setFill];//设置填充颜色

   [path fill];

   [path stroke];

}

奇偶填充规则:

当有两个或以上的图形叠加的时候,叠加的部分,如果是叠加了偶数次,则不给填充

- (void)drawRect:(CGRect)rect{

   CGContextRef ctx = UIGraphicsGetCurrentContext();

   UIBezierPath *juxing = [UIBezierPath bezierPathWithRect:CGRectMake(10, 10, 30, 50)];

   UIBezierPath *yuan = [UIBezierPath bezierPathWithArcCenter:CGPointMake(25, 35) radius:15 startAngle:0 endAngle:M_PI* 2 clockwise:YES];

   UIBezierPath *juxing1 = [UIBezierPath bezierPathWithRect:CGRectMake(5, 5, 50, 50)];

   CGContextAddPath(ctx, juxing.CGPath);

   CGContextAddPath(ctx, yuan.CGPath);

   CGContextAddPath(ctx, juxing1.CGPath);

   CGContextDrawPath(ctx, kCGPathEOFill);

}

非0环绕数规则:默认的填充方式,从左到右开跨过,+1.从右到左跨过-1.如果最后为0,那么不填充,否则填充

- (void)drawRect:(CGRect)rect{

   CGContextRef ctx = UIGraphicsGetCurrentContext();

   UIBezierPath *yuan = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 50) radius:50 startAngle:0 endAngle:M_PI* 2 clockwise:YES];

   UIBezierPath *yx = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 50) radius:30 startAngle:0 endAngle:M_PI * 2 clockwise:NO];

   CGContextAddPath(ctx, yuan.CGPath);

   CGContextAddPath(ctx, yx.CGPath);

   CGContextDrawPath(ctx, kCGPathFill);

}

10.绘制饼状图:

.m文件:

#import <UIKit/UIKit.h>

@interface BingtuUIView : UIView

@property(nonatomic,strong) NSArray *data;

@property(nonatomic,strong) NSArray<UIColor *> *colors;

- (instancetype)initWithFrame:(CGRect)frame andData :(NSArray*) data andColors:(NSArray<UIColor*>*) colors;

@end

.h文件:

#import "BingtuUIView.h"

@implementation BingtuUIView

- (instancetype)initWithFrame:(CGRect)frame andData :(NSArray*) data andColors:(NSArray<UIColor*>*) colors{

if(frame.size.height != frame.size.width){

       //如果控件的高度和宽度不一样,则抛出异常

       [NSException raise:@"饼状图的宽度和高度必须一样" format:@"不一样的话,显示不好看"];

   }

   self = [super initWithFrame:frame];

   if (self) {

       self.data = data;

       self.colors = colors;

       return self;

   }

   return nil;

}

//模拟数据

- (NSArray *)data{

   if (!_data) {

       _data = @[@30,@20,@20,@30];

   }

   return _data;

}

- (NSArray<UIColor *> *)colors{

   if (!_colors) {

       _colors = [NSArray arrayWithObjects:[UIColor redColor],[UIColor whiteColor],[UIColor blueColor],[UIColor orangeColor], nil];

   }

   return _colors;

}

- (void)drawRect:(CGRect)rect{

   int sum = 0;

   for (id num in self.data) {

       sum += [num floatValue];

   }

   float star = 0,end= 0;

   for (int i = 0; i< self.data.count;i++) {

        end = 2 * M_PI * ([self.data[i] floatValue] / sum) + star;

       UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2) radius: (self.bounds.size.height < self.bounds.size.width ? self.bounds.size.height:self.bounds.size.width) / 2  startAngle:star endAngle:end clockwise:YES];

       [path addLineToPoint:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2)];

       [self.colors[i] setFill];

       [path fill];

       star = end;

   }

}

@end

使用:

- (BingtuUIView *)bing{

   if (!_bing) {

       _bing = [[BingtuUIView alloc] initWithFrame:CGRectMake(75, 75, 150 , 150) andData:@[@10,@38,@40,@30] andColors:@[[UIColor redColor],[UIColor blueColor],[UIColor orangeColor],[UIColor whiteColor]]];

       _bing.backgroundColor = [UIColor yellowColor];

   }

   return _bing;

}

等学会了画字符串再把字符串加上.

11.绘制柱状图:

.h文件:

#import <UIKit/UIKit.h>

@interface ZhuTuUIView : UIView

@property(nonatomic,strong) NSArray *data;

@property(nonatomic,strong) NSArray<UIColor*> *colors;

- (instancetype)initWithFrame:(CGRect)frame andData:(NSArray *)data andColors:(NSArray<UIColor*>*) colors;

@end

.m文件:

@implementation ZhuTuUIView

- (instancetype)initWithFrame:(CGRect)frame andData:(NSArray *)data andColors:(NSArray<UIColor *> *)colors{

   if(data.count != colors.count){

       [NSException raise:@"" format:@""];

   }

   self = [super initWithFrame:frame];

   if (self) {

       self.data = data;

       self.colors = colors;

       return self;

   }

   return nil;

}

- (void)drawRect:(CGRect)rect{

   //计算出data中的最大数

   float max = [self.data[0] floatValue];

   for (id num in self.data) {

       float numfloat = [num floatValue];

       max = max > numfloat ? max:numfloat;

   }

   float kdu =  self.bounds.size.width / (self.data.count * 2 - 1);//100/8=12.5

   float value = self.bounds.size.height / max;//100/40 = 2.5

   for (int i = 0; i < self.data.count; i++) {

       UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake((i - 1) * 2 * kdu + 2 * kdu , self.bounds.size.height - [self.data[i] floatValue] * value + 20, kdu, [self.data[i] floatValue] * value)];

       [self.colors[i] setFill];

       [path fill];

   }

}

@end

使用:

- (ZhuTuUIView *)zhuTu{

   if (!_zhuTu) {

       _zhuTu = [[ZhuTuUIView alloc] initWithFrame:CGRectMake(75, 75, 150 , 100) andData:@[@20,@25,@28,@30,@29,@50] andColors:@[[UIColor redColor],[UIColor blueColor],[UIColor orangeColor],[UIColor whiteColor],[UIColor brownColor],[UIColor blackColor]]];

       _zhuTu.backgroundColor = [UIColor yellowColor];

   }

   return _zhuTu;

}

12.自定义进度条:

.h文件:

#import <UIKit/UIKit.h>

@interface LoadingUIView : UIView

@property(nonatomic,assign) float value;

@property(nonatomic,assign) float maxValue;

@property(nonatomic,strong) UIColor *color;

- (instancetype)initWithFrame:(CGRect)frame addVale:(float) value addMaxVale:(float) maxValue addColor :(UIColor *) color;

@end

.m文件:

#import "LoadingUIView.h"

@interface LoadingUIView ()

@property(nonatomic,strong) UILabel *label;

@end

@implementation LoadingUIView

- (UILabel *)label{

   if(!_label){

       _label = [[UILabel alloc] initWithFrame:CGRectMake(self.bounds.size.width / 2 - 20, self.bounds.size.height / 2 - 10, 40, 20)];

       //_label.backgroundColor = [UIColor colorWithRed:1 green:0 blue:1 alpha:1];

       [_label setTextColor:[UIColor blueColor]];

   }

   return _label;

}

- (instancetype)initWithFrame:(CGRect)frame addVale:(float)value addMaxVale:(float) maxValue  addColor:(UIColor *)color{

   self = [super initWithFrame:frame];

   if(self){

       self.value = value;

       self.color = color;

       self.maxValue = maxValue;

       [self addSubview:self.label];

       return self;

   }

   return nil;

}

- (void)drawRect:(CGRect)rect{

   UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2) radius:(self.bounds.size.height < self.bounds.size.width ? self.bounds.size.height:self.bounds.size.width) / 2 startAngle:0 endAngle: 2 * M_PI * (self.value / self.maxValue) clockwise:YES];

   [path addLineToPoint:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2)];

   self.label.text = [NSString stringWithFormat:@"%0.0lf%%",self.value * 100 / self.maxValue];

   [self.color setFill];

   [path fill];

}

@end

使用:

- (LoadingUIView *)loading{

   if (!_loading) {

       _loading = [[LoadingUIView alloc]initWithFrame:CGRectMake(75, 75, 150 , 150) addVale: 0 addMaxVale:100 addColor:[UIColor redColor]];

       _loading.backgroundColor = [UIColor yellowColor];

   }

   return _loading;

}

- (void)viewDidLoad {

   [super viewDidLoad];

   [self.view addSubview:self.loading];

   UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(self.view.bounds.size.width / 6, 300, self.view.bounds.size.width / 3 * 2, 10)];

   slider.value = 0;

   slider.maximumValue = 100;

   slider.minimumValue = 0;

   [slider addTarget:self action:@selector(sliderChage:) forControlEvents:UIControlEventValueChanged];

   [self.view addSubview:slider];

}

- (void) sliderChage:(UISlider*)slider{

   float value = slider.value;

   self.loading.value = value;

   [self.loading setNeedsDisplay];

}

13.矩形操作:

其实是对上下文进行操作:

- (void)drawRect:(CGRect)rect{

   CGContextRef ctx = UIGraphicsGetCurrentContext();

   //旋转

   CGContextRotateCTM(ctx, M_PI_4 / 10);

   //缩放

   CGContextScaleCTM(ctx, 0.5, 0.5);

   //平移

   CGContextTranslateCTM(ctx, 20, 60);

   UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(10, 10, 50,  80)];

   [[UIColor redColor] setFill];

   [path fill];

   UIBezierPath *path1 = [[UIBezierPath alloc]init];

   [path1 moveToPoint:CGPointMake(0, 0)];

   [path1 addLineToPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height)];

   [path1 stroke];

}

14.图形上下文栈:

15.quartz2d内存管理

16.绘制文字:

- (void)drawRect:(CGRect)rect{

   //文字对象

   NSString *str = @"你好,闻品高";

//    [str drawAtPoint:CGPointMake(10, 10) withAttributes:nil];

   [str drawInRect:CGRectMake(5, 50, 80, 50) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:20],NSForegroundColorAttributeName:[UIColor redColor]}];

}

17.绘制图片:

- (void)drawRect:(CGRect)rect{

   UIImage *image = [UIImage imageNamed:@"psb.png"];

   //小图的绘制

//    [image drawAtPoint:CGPointMake(0, 0)];//从某个点开始绘制

//    [image drawInRect:rect];//将图片绘制到某个区域,拉伸的

//    [image drawAsPatternInRect:rect];//将图片绘制到某个区域,平铺

   //大图的绘制

   [image drawAsPatternInRect:rect];

}

18.裁剪上下文的显示区域:

- (void)drawRect:(CGRect)rect{

   UIImage *image = [UIImage imageNamed:@"psb.png"];

   CGContextAddArc(UIGraphicsGetCurrentContext(), self.bounds.size.width / 2, self.bounds.size.height / 2, (self.bounds.size.width > self.bounds.size.height ? self.bounds.size.height : self.bounds.size.width) / 2, 0, 2* M_PI, 1);//限定裁剪的区域

   CGContextClip(UIGraphicsGetCurrentContext());//裁剪

   [image drawInRect:rect];

}

19.Bitmap上下文:

1.开启图片的图形上下文

2.绘制简单图形

3.关闭图片的图形上下文

4.保存到沙盒中

1.把图片转为NSDataduix

2.调用data的writertofile方法

//声明属性

@property(nonatomic,strong) UIImageView *imageView;

//加载

- (UIImageView *)imageView{

   if (!_imageView) {

       _imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"psb"]];

       _imageView.frame = self.view.bounds;

   }

   return _imageView;

}

//添加到view上

    [self.view addSubview:self.imageView];

//点击屏幕时,发生

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

   //开启一个图片类型的上下文

//    UIGraphicsBeginImageContext(CGSizeMake(200, 200));

   UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 1);

   //获取当前上下文

   CGContextRef  ctx = UIGraphicsGetCurrentContext();

   [[UIColor redColor] setStroke];

   CGContextAddArc(ctx, 100, 100, 100, 0, 2 * M_PI, 1);//画圆

   CGContextStrokePath(ctx);//渲染

   UIImage *img = UIGraphicsGetImageFromCurrentImageContext();//输出到图片

   UIGraphicsEndImageContext();//关闭图片图形上下文

   self.imageView.image = img;//添加到界面

   //获取doc目录

   NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES)[0];

   NSString *file = [path stringByAppendingString:@"1.jpg"];

   //保存到沙盒

   NSData * data = UIImageJPEGRepresentation(img, 1);

   [data writeToFile:file atomically:YES];

}