天天看點

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];

}