Quartz 2D (1)

一右锨、繪制基本圖形

1括堤、Quartz 2D是一個二維繪圖引擎,同時支持iOS和Mac系統(tǒng)(Quartz 2D是封裝好一套繪圖的庫绍移,里面放有很多繪圖框架提供使用)
Quartz 2D在ios開發(fā)中很重要的價值就是自定義view(自定義UI控件)
Quartz 2D能完成的工作:
1>繪制圖形 : 線條\三角形\矩形\圓\弧等
2>繪制文字
3>繪制\生成圖片(圖像)
4>讀取\生成PDF
5>截圖\裁剪圖片
6>自定義UI控件(最大的作用自定義view)

為了便于搭建美觀的UI界面悄窃,iOS提供了UIKit框架,里面有各種各樣的UI控件
UILabel:顯示文字
UIImageView:顯示圖片
UIButton:同時顯示圖片和文字(能點擊)
… …

利用UIKit框架提供的控件蹂窖,拼拼湊湊轧抗,能搭建和現(xiàn)實一些簡單、常見的UI界面

但是瞬测,有些UI界面極其復雜横媚、而且比較個性化,用普通的UI控件無法實現(xiàn)月趟,這時可以利用Quartz2D技術(shù)將控件內(nèi)部的結(jié)構(gòu)畫出來灯蝴,自定義控件的樣子

其實,iOS中大部分控件的內(nèi)容都是通過Quartz2D畫出來的

因此孝宗,Quartz2D在iOS開發(fā)中很重要的一個價值是:自定義view(自定義UI控件)
Quartz 2D能做很多強大的事情,例如

裁剪圖片
涂鴉\畫板
手勢解鎖
2穷躁、圖形上下文(Graphics Context):是一個CGContextRef類型的數(shù)據(jù)
圖形上下文的作用
保存繪圖信息、繪圖狀態(tài)
圖形上下文類型不同決定繪制的輸出目標(繪制到什么地方去碳褒?)
(輸出目標可以是PDF文件折砸、Bitmap或者顯示器的窗口上)

相同的一套繪圖序列看疗,指定不同的Graphics Context,就可將相同的圖像繪制到不同的目標上

Quartz2D提供了以下幾種類型的Graphics Context:
Bitmap Graphics Context
PDF Graphics Context
Window Graphics Context
Layer Graphics Context
Printer Graphics Context

如何利用Quartz2D自定義view睦授?(自定義UI控件)

如何利用Quartz2D繪制東西到view上两芳?
首先,得有圖形上下文去枷,因為它能保存繪圖信息怖辆,并且決定著繪制到什么地方去
其次,那個圖形上下文必須跟view相關(guān)聯(lián)删顶,才能將內(nèi)容繪制到view上面


以下實現(xiàn)的是Layer Graphics Context類型的:
自定義view的步驟:
1>新建一個類竖螃,繼承自UIView
2>實現(xiàn)- (void)drawRect:(CGRect)rect方法(此方法中默認自動生成一個與view相關(guān)聯(lián)的圖形上下文)
3>在這個方法中取得跟當前view相關(guān)聯(lián)的圖形上下文
4>繪制相應的圖形內(nèi)容
5>利用圖形上下文將繪制的所有內(nèi)容渲染顯示到view上面

為什么要實現(xiàn)drawRect:方法才能繪圖到view上?
因為在drawRect:方法中才能取得跟view相關(guān)聯(lián)的圖形上下文

drawRect:方法在什么時候被調(diào)用逗余?
當view第一次顯示到屏幕上時調(diào)用(被加到UIWindow上顯示出來)
調(diào)用view的setNeedsDisplay或者setNeedsDisplayInRect:時

Quartz2D的API是純C語言的特咆,Quartz2D的API來自于Core Graphics框架


數(shù)據(jù)類型和函數(shù)基本都以CG作為前綴
CGContextRef
CGPathRef
CGContextStrokePath(ctx);


在drawRect:方法中取得上下文后,就可以繪制東西到view上

具體實現(xiàn)步驟:
1>自定義View
2>在view的根類中實現(xiàn)- (void)drawRect:(CGRect)rect 方法
3>在方法中=>
- (void)drawRect:(CGRect)rect
{
(1)畫線
//獲取圖形上下文(獲取录粱,創(chuàng)建上下文腻格,都以UIGraphics開頭)
CGContextRef context = UIGraphicsGetCurrentContext();
//繪制路徑
UIBezierPath *path = [UIBezierPath bezierPath];
//設(shè)置起點
[path moveToPoint:CGPointMake(50, 50)];
//添加一根線到終點
[path addLineToPoint:CGPointMake(100, 100)];
//設(shè)置線的顏色
[[UIColor redColor] set];
//設(shè)置線的寬度
CGContextSetLineWidth(context, 20);
//把繪制的內(nèi)容添加到上下文當中
CGContextAddPath(context, path.CGPath);
//把上下文的內(nèi)容顯示到View上(渲染到View的layer)
CGContextStrokePath(context);
//CGContextFillPath(context);

(2)曲線
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIBezierPath *path = [UIBezierPath bezierPath];

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

//controlPoint控制點
[path addQuadCurveToPoint:CGPointMake(100, 100) controlPoint:CGPointMake(50, 30)];
CGContextAddPath(ctx, path.CGPath);
CGContextStrokePath(ctx);

(3)畫三角形

 CGContextRef context = UIGraphicsGetCurrentContext();
 //繪制路徑
 UIBezierPath *path = [UIBezierPath bezierPath];
 //設(shè)置起點
 [path moveToPoint:CGPointMake(50, 50)];
 //添加一根線到終點,并且以終點作為起點再畫一條線
 [path addLineToPoint:CGPointMake(100, 100)];
 [path addLineToPoint:CGPointMake(50, 200)];
 //設(shè)置線的顏色
 [[UIColor redColor] set];
 //線的冒冒設(shè)置為圓角
 CGContextSetLineCap(context, kCGLineCapRound);
 //設(shè)置線的寬度
 CGContextSetLineWidth(context, 5);
 //把繪制的內(nèi)容添加到上下文當中
 CGContextAddPath(context, path.CGPath);
 //終點與起點閉合
 CGContextClosePath(context);
 //把上下文的內(nèi)容顯示到View上(渲染到View的layer)
 CGContextStrokePath(context);
 //CGContextFillPath(context);(Fill有填充及自動關(guān)閉路徑的功能)

 (4)畫矩形
 1>//獲取圖形上下文(獲取菜职,創(chuàng)建上下文,都以UIGraphics開頭)
 CGContextRef context = UIGraphicsGetCurrentContext();
  UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 50, 100)];(寬高一樣就是正方形)
 2>只寫下面方法能快速填充出一個矩形
   [[UIColor redColor]set];
   UIRectFill(CGRectMake(50, 50, 50, 50));
 
 
  (5)圓角矩形(如果當前的矩形是正方形設(shè)置圓角半徑等于寬畫成圓了旗闽,如果不是正方形酬核,設(shè)置圓角半徑等于寬畫成橢圓)
  UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 100, 100) cornerRadius:20];
   [[UIColor redColor]set];
   CGContextAddPath(ctx, path.CGPath);
   //CGContextStrokePath(ctx);
   CGContextFillPath(ctx);(填充)
 
  (6)畫橢圓(寬高一樣,畫成圓)
 //注意:以后使用以下的寫法适室,可以省列很多步驟
  UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 100, 50)];
  [path stroke];//(該方法中封裝了以下步驟:1嫡意、獲取上下文 2、描述路徑 3亭病、把路徑添加到上下文 4鹅很、把上下文的內(nèi)容渲染到view上)
  [path fill];(填充)//跟以上同有封裝功能
 
 (7)畫弧
 //參數(shù)Center:弧所在的圓心
 //參數(shù)radius:圓的半徑
 //參數(shù)startAngle:開始的角度
 //參數(shù)endAngle:截止角度
 //參數(shù)clockwise:YES順時針 NO:逆時針
 
 //注意:不能直接調(diào)用父類的self.center,是因為self.center坐標是相對于它的父控件罪帖,不能使用促煮,必須要使用自定義view的坐標,drawRect方法提供的參數(shù)rect就是自定義view的范圍
 CGPoint center =CGPointMake(rect.size.width *0.5, rect.size.height *0.5);
 CGFloat radius =rect.size.width *0.5 - 10;
 
 UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius  startAngle:M_PI_2 endAngle:-M_PI_2 clockwise:YES];
 
 [path stroke];
 
 (8)扇形
 //參數(shù)Center:弧所在的圓心
 //參數(shù)radius:圓的半徑
 //參數(shù)startAngle:開始的角度
 //參數(shù)endAngle:截止角度
 //參數(shù)clockwise:YES順時針 NO:逆時針
 CGPoint center =CGPointMake(rect.size.width *0.5, rect.size.height *0.5);
 CGFloat radius =rect.size.width *0.5 - 10;
 
 UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius  startAngle:- M_PI endAngle:-M_PI_2 clockwise:YES];
 [path addLineToPoint:center];
 [[UIColor redColor]set];
 //    [path closePath];
 //    [path stroke];
 [path fill];
 
 (9)畫文字
 NSString *str = @"我愛您sdgsdgsdgfdbfdsfagsdgsg";
 
     NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
     dictM[NSFontAttributeName] = [UIFont systemFontOfSize:50 weight:20];
     dictM[NSForegroundColorAttributeName] = [UIColor redColor];
     //描邊
     dictM[NSStrokeWidthAttributeName] = @3;
     dictM[NSStrokeColorAttributeName] = [UIColor blueColor];
     //設(shè)置陰影
     NSShadow *shadow = [[NSShadow alloc]init];
     shadow.shadowColor = [UIColor orangeColor];
     shadow.shadowOffset = CGSizeMake(1, 2);
     
     dictM[NSShadowAttributeName] = shadow;
 
 //[str drawAtPoint:CGPointMake(0, 0) withAttributes:dictM];
 [str drawInRect:rect withAttributes:dictM];//此方法會自動換行
 
 (10)畫圖片
 UIImage *image = [UIImage imageNamed:@"people_wangxinling"];
 //  UIRectClip(CGRectMake(0, 0, 50, 50));(裁剪,必須在繪制之前進行設(shè)置)
 // [image drawInRect:rect];(把藥繪制的圖片給填充給定的區(qū)域當中)
 //    [image drawAtPoint:CGPointMake(0, 0)];//(繪制的是原始圖片的大小)

 [image drawAsPatternInRect:rect];(平鋪)
(11)餅圖(在自定義view的跟類中實現(xiàn))
 - (void)drawRect:(CGRect)rect {
     
     NSArray *arr = @[@25,@25,@50];
     CGPoint center = CGPointMake(rect.size.width *0.5, rect.size.height *0.5);
     CGFloat radius = rect.size.width *0.5 - 10;
     
     CGFloat startA = 0;
     CGFloat angle = 0;
     CGFloat endA = 0;
     for (NSNumber *num in arr) {
         
         startA = endA;
         angle = num.intValue/100.0 *M_PI *2;
         endA = startA + angle;
         
         UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius: radius startAngle:startA endAngle:endA clockwise:YES];
         [[self radamColor]set];
         [path addLineToPoint:center];
         [path fill];
         
     }
 }

 - (UIColor *)radamColor
 {
     CGFloat r = arc4random_uniform(256)/255.0;
     CGFloat g = 0;
     CGFloat b = 0;
     while ( r == g) {
         g = arc4random_uniform(256)/255.0;
     }
     while ( r == g == b) {
         b = arc4random_uniform(256)/255.0;
     }
     return [UIColor colorWithRed:r green:g  blue:b  alpha:1.0];
     
 }

 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
 {
     [self setNeedsDisplay];
}
3整袁、下載進度條例子實現(xiàn)
      //%在stringWithFormat有特殊含義菠齿,不能直接使用,如果想要使用用兩個%代表一個%
      self.LabelSlider.text = [NSString stringWithFormat:@"%.2f%%", sender.value];

  (2)注意:- (void)drawRect:方法如果是手動調(diào)用的話坐昙,它是不會給你創(chuàng)建view相關(guān)聯(lián)的上下文绳匀,只有系統(tǒng)調(diào)用該方法時,才會創(chuàng)建跟view相關(guān)聯(lián)的上下文,所以一般使用以下方法疾棵,讓系統(tǒng)自動調(diào)用- (void)drawRect:方法
      [self setNeedsDisplay];
4戈钢、新的定時器(不使用NSTimer,在自定義view的跟類中實現(xiàn))
- (void)awakeFromNib
{
    [super awakeFromNib];
     //舊的定時器
     //[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(changeY) userInfo:nil repeats:YES];
    
     //新的定時器
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeY)];
    //想要讓CADisplayLink讓它工作是尔,必須要把他添加到主運行循環(huán)當中
    //當每一次屏幕刷新的時候就會調(diào)用指定的方法(屏幕每一秒刷新60次)
    [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}

CGFloat cc = 0;

- (void)changeY
{
    cc += 10;
    
    if (cc > self.bounds.size.height) {
        cc = 0;
    }
    //setNeedsDisplay會調(diào)用drawRect:方法殉了,但是它并不是立馬調(diào)用,只是設(shè)了一個表示拟枚,當下一次屏幕刷新的時候才會調(diào)用drawRect:方法薪铜,所以與上面新的定時器同步跑時看起來比較順滑
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    
    UIImage *image = [UIImage imageNamed:@"people_wangxinling"];
    
    [image drawInRect:CGRectMake(0, cc, 50, 50)];
    
}
5、圖形上下文棧(面試題)
(1)//一執(zhí)行下面的方法恩溅,就會獲取跟view相關(guān)聯(lián)的上下文隔箍,在內(nèi)存中分配存儲空間
   //上下文在內(nèi)存中的結(jié)構(gòu)分為上下兩個區(qū)域:1>上面區(qū)域是保存路徑,2>下面區(qū)域是保存上下文的狀態(tài)(默認此區(qū)域的線寬為1脚乡,顏色為黑色)
CGContextRef ctx = UIGraphicsGetCurrentContext();

(2)//描述路徑
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(20, 20)];
[path addLineToPoint:CGPointMake(60, 60)];

//以下代碼對上下文狀態(tài)區(qū)域的狀態(tài)進行修改
CGContextSetLineWidth(ctx, 10);
[UIColor redColor] set];

(3)//把路徑添加到上下文中(當執(zhí)行完這行代碼蜒滩,就把線添加到上下文保存路徑的區(qū)域)
CGContextAddPath(ctx, path.CGPath);
//

(4)//把上下文中的內(nèi)容渲染到view當中
當執(zhí)行次操作:會到上下文內(nèi)存的保存路徑的區(qū)域取出全部內(nèi)容,然后把保存在上下文狀態(tài)區(qū)域里的狀態(tài)設(shè)置給取出的內(nèi)容
CGContextStrokePath(ctx);
CGContextFillPath(ctx);


補一://保存當前上下文的狀態(tài)(當執(zhí)行此代碼每窖,就把上下文狀態(tài)區(qū)域里的狀態(tài)復制一份保存到狀態(tài)棧中)
    CGContextSaveGState(ctx);
補二://從上下文狀態(tài)棧當中恢復上下文的狀態(tài)(執(zhí)行此代碼帮掉,取出上下文狀態(tài)棧中最上面的狀態(tài)來進行設(shè)值,并且恢復上下文狀態(tài)區(qū)域的狀態(tài)為上下文狀態(tài)棧中最上面的狀態(tài))
    CGContextRestoreGState(ctx);
6窒典、圖形上下文的矩陣操作
   CGContextTranslateCTM(ctx, 10, 10);
   //旋轉(zhuǎn)(最常用)
   CGContextRotateCTM(ctx, M_PI);
   //縮放
   CGContextScaleCTM(ctx, 1.5, 1.5);
7、圖片加水印(是生成一張新的圖片稽莉,在任何地方都可實現(xiàn)瀑志,不是在view上畫東西,所以不需要在 - (void)drawRect:(CGRect)rect實現(xiàn))
位圖上下文需要手動去開啟污秆,開啟多大的上下文劈猪,生成的圖片就多大

//0、加載圖片
UIImage *image = [UIImage imageNamed:@"people_caoying"];

//1良拼、開啟一個跟圖片原始大小的上下文
//參數(shù):opaque不透明
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);

//2.把圖片繪制到上下文當中
[image drawAtPoint:CGPointZero];

//3.把文字繪制到上下文當中
NSString *str = @"x阿貝";
NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
dictM[NSFontAttributeName] = [UIFont systemFontOfSize:100 weight:20];
dictM[NSForegroundColorAttributeName] = [UIColor redColor];
[str drawAtPoint:CGPointMake(10,20) withAttributes:dictM];

//4.從上下文當中生成一張新的圖片
UIImage *newimage = UIGraphicsGetImageFromCurrentImageContext();

//5.關(guān)閉上下文
UIGraphicsEndPDFContext();
self.imageV.image = newimage;

Mode參數(shù)決定繪制的模式
void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode)

繪制空心路徑
void CGContextStrokePath(CGContextRef c)

繪制實心路徑
void CGContextFillPath(CGContextRef c)

提示:一般以CGContextDraw战得、CGContextStroke、CGContextFill開頭的函數(shù)庸推,都是用來繪制路徑的

將當前的上下文copy一份,保存到棧頂(那個棧叫做”圖形上下文棾U欤”)
void CGContextSaveGState(CGContextRef c)

將棧頂?shù)纳舷挛某鰲?替換掉當前的上下文
void CGContextRestoreGState(CGContextRef c)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市贬媒,隨后出現(xiàn)的幾起案子聋亡,更是在濱河造成了極大的恐慌,老刑警劉巖际乘,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坡倔,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機罪塔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門投蝉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人征堪,你說我怎么就攤上這事瘩缆。” “怎么了请契?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵咳榜,是天一觀的道長。 經(jīng)常有香客問我爽锥,道長涌韩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任氯夷,我火速辦了婚禮臣樱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腮考。我一直安慰自己雇毫,他們只是感情好,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布踩蔚。 她就那樣靜靜地躺著棚放,像睡著了一般。 火紅的嫁衣襯著肌膚如雪馅闽。 梳的紋絲不亂的頭發(fā)上飘蚯,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機與錄音福也,去河邊找鬼局骤。 笑死,一個胖子當著我的面吹牛暴凑,可吹牛的內(nèi)容都是我干的峦甩。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼现喳,長吁一口氣:“原來是場噩夢啊……” “哼凯傲!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拿穴,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤泣洞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后默色,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體球凰,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡狮腿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了呕诉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缘厢。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖甩挫,靈堂內(nèi)的尸體忽然破棺而出贴硫,到底是詐尸還是另有隱情,我是刑警寧澤伊者,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布英遭,位于F島的核電站,受9級特大地震影響亦渗,放射性物質(zhì)發(fā)生泄漏挖诸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一法精、第九天 我趴在偏房一處隱蔽的房頂上張望多律。 院中可真熱鬧,春花似錦搂蜓、人聲如沸狼荞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽相味。三九已至,卻和暖如春殉挽,著一層夾襖步出監(jiān)牢的瞬間攻走,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工此再, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人玲销。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓输拇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贤斜。 傳聞我的和親對象是個殘疾皇子策吠,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容