一、Quartz2D基本概念
1、Quartz2D是一個二維圖形繪制引擎,支持iOS環境和Mac OS X環境
2、Quartz2D API可以實現很多功能,如基于路徑的繪圖、透明度、陰影、顏色管理、反鋸齒、PDF文檔生成和PDF元數據訪問等
3、Quartz2D API是Core Graphics框架的一部分,因此其中的很多數據類型和方法都是以CG開頭的
4、Quartz2D與分辨率和設備無關,因此在使用Quartz2D繪圖時,無需考慮最終繪圖的目標設備
二、Core Graphics? ??
1、該框架是一組基于C的API,可以用于一切繪圖操作,這個框架的重要性,僅次于UIKit和Foundation? ??
2、當使用UIKit創建按鈕、標簽或者其他UIView的子類時,UIKit會用Core Graphics將這些元素繪制在屏幕上,此外,UIEvent也會使用Core Graphics,用來幫組確定觸摸時間在屏幕上所處的位置? ??
3、因為UIKit依賴于Core Graphics,所以當引入時,Core Graphics框架會被自動引入
4、為了讓開發者不必觸及底層的Core Graphics的C接口,UIKit內部封裝了Core Graphics的一些API,可以快速生成通用的界面元素,但是,有時候直接利用Core Graphics的C接口是很有必要和很有好處的,比如創建一個自定義的界面元素
三、Quartz2D的幾個重要概念
1、圖像上下文(Graphics Context) - 相當于一個畫筆
1) Graphics Context是一個數據類型(CGContextRef),封裝了Quartz繪制圖像到輸出設備的信息,輸出設備可以是PDF文件、Bitmap(位圖文件,一種圖形文件)或者顯示器的窗口上
2)Quartz中所有的對象都是繪制到一個Graphics Context中
3)當用Quartz繪圖時,所有設備相關的特性都包含在Graphics Context中,換句話說,我們可以簡單地給Quartz繪圖序列指定不同的Graphics Context,就可將相同的圖像繪制在不同的設備上,而不需要任何設備相關的計算,這些都有Quartz替我們完成
2、Quartz2D坐標系
1)Quartz中默認的坐標系統是:原定(0,0)在左下角,沿著X軸從左到右坐標值逐漸增大,沿著Y軸從下到上左鍵增加
2)有些技術在設置他們的graphics Context時使用了不同于Quartz的默認坐標系統,最常見的是系統原點修改為左上角
3)坐標系的轉換
//相對原點旋轉上下文坐標系
CGContextRotateCTM(CGContextRef c, CGFloat angle)
//相對原點平移上下文坐標系
CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
//縮放上下文坐標系
CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)
PS:
注意:
轉換坐標系前,使用方法保存當前上下文狀態
CGContextSaveGState(CGContextRef c)
坐標系轉換后,使用方法恢復之前保存的上下文狀態
CGContextRestoreGState(CGContextRef c)可以
3、Quartz2D的繪圖順序
1)誰后繪制誰顯示在頂部,即疊加到最上面
2)利用Quartz2D繪制UIView
當在UIView子類中重寫drawRect方法時,iOS會自動準備好一個圖像上下文,可以通過調用UIGraphicsGetCurrentContext()來獲取
3)只要一個UIView需要被刷新或者重繪,drawRect方法就會被調用,需要注意的是:重繪時應該調用setneedsDisplay,而不能直接調用drawRect,setNeedsDisplay會自動調用drawRect:
4) drawRect注意事項
drawRect:是在UIViewController的loadView和viewDidLoad兩方法之后調用的
drawRect:如果試圖沒有設置frame,將導致該方法不能執行
如果設置UIView的contentMode屬性值為UIViewContentModeRedraw,那么將在每次更改frame時自動調用drawRect:
如果使用UIView繪圖,只能在drawRect:方法中獲取相應的CGContextRef并繪圖,而在其他方法中獲取的CGContextRef不能用于繪圖
4、Quartz內存管理
1)使用含有"Create"或"Copy"的函數創建的對象,使用完后必須釋放,否則將導致內存泄露,使用不含有"Create"或"Copy"的函數獲取的對象,則不需要釋放
2)如果retain了一個對象,不再使用時需要將其release掉,可以使用Quratz2D的函數來指定retain和release一個對象,例如創建了一個CGColorSpace對象,則使用函數CGColorSpaceRetain和CGColorSpaceRelease來retain和release對象,也可以使用CoreFoundation的CFRetain和CGRelease。注意不能傳遞NULL值給這些函數
5、Quartz2D繪圖的基礎元素-路徑
路徑定義了一條或者多條形狀或子路徑
子路徑可以包含一條或者多條直線或曲線
子路徑也可以是一些簡單的形狀,例如線、圓形、矩形或者星型等
子路徑還可以包含復雜的形狀,例如地圖輪廓或者涂鴉等
路徑是可以是開放的,也可以是封閉的,對于封閉路徑可以是空心的也可以是實心的
四、練習,都是在drawRect方法內操作
1、基本繪圖,使用Path實現
1)獲取與試圖相關聯的上下文對象
//提示:使用Ref聲明的對象,不需要用*
CGContextRef context = UIGraphicsGetCurrentContext();
2)創建及設置路徑(path)
創建路徑
CGMutablePathRef path = CGPathCreateMutable();
設置路徑起點
CGPathMoveToPoint(path, NULL, 50, 50);
增加路徑內容
CGPathAddLineToPoint(path, NULL, 200,200);
CGPathAddLineToPoint(path, NULL, 50, 200);
封閉路徑
CGPathAddLineToPoint(path, NULL, 50, 50);
CGPathCloseSubpath(path);
上面這兩個函數都可以用來封閉路徑,但后者在設置頂點樣式時會使樣式無效
3) 將路徑添加到上下文
CGContextAddPath(context, path);
4)設置上下文狀態
邊線顏色
CGContextSetRGBStrokeColor(context, 0.7, 0.7, 0.5, 1);
填充顏色
CGContextSetRGBFillColor(context, 1, 0, 0, 1);
線寬
CGContextSetLineWidth(context, 10);
設置線條的頂點樣式
CGContextSetLineCap(context, kCGLineCapButt);
設置線條的連接點樣式
CGContextSetLineJoin(context, kCGLineJoinRound);
設置線條的虛線樣式
context
phase 相位,虛線起始的位置,通常使用0即可,從頭開始畫虛線
lengths 長度的數組
count lengths數組的個數
CGFloat lengths[4] = {40.0, 40.0};
CGContextSetLineDash(context, 0.0, lengths, 2);
5)繪制路徑
kCGPathStroke: 畫線(空心)
kCGPathFill:? 填充(實心)
kCGPathFillStroke: 即畫線又填充
CGContextDrawPath(context, kCGPathFillStroke);
6)釋放路徑
CGPathRelease(path);
2、基本繪圖,上下文的默認路徑實現
1)獲取上下文
CGContextRef context = UIGraphicsGetCurrentContext();
2)設置當前上下文的路徑
設置路徑起點
CGContextMoveToPoint(context, 50, 50);
增加路徑內容
CGContextAddLineToPoint(context, 200, 200);
CGContextAddLineToPoint(context, 50, 200);
封閉路徑
CGContextClosePath(context);
CGContextAddLineToPoint(context, 50, 50);
3) 設置上下文狀態
CGContextSetLineWidth(context, 10); //線條寬
CGContextSetLineJoin(context, kCGLineJoinRound); //連接點樣式
CGContextSetLineCap(context, kCGLineCapRound);? //頂點樣式
4)繪制路徑,雖然沒有直接定義路徑,但是第二步操作,就是為上下文指定路徑
CGContextDrawPath(context, kCGPathFillStroke);
3、繪制矩形
CGRect rect = CGRectMake(50, 50, 200, 200);
[[UIColor redColor] setStroke];
[[UIColor grayColor] setFill];
//繪制實心矩形
UIRectFill(rect);
//繪制空心矩形
UIRectFrame(rect);
4、繪制圓形
1. 取出上下文
CGContextRef context = UIGraphicsGetCurrentContext();
2. 設置路徑
CGRect rect = CGRectMake(50, 50, 200, 200);
Ellipse圓形
CGContextAddEllipseInRect(context, rect);
3. 繪制路徑
CGContextDrawPath(context, kCGPathFillStroke);
5、繪制弧度
CGContextRef context = UIGraphicsGetCurrentContext();
context 上下文
x,y 是圓弧所在圓的中心點坐標
radius 半徑,所在圓的半徑
startAngle endAngle 起始角度和截止角度 單位是弧度 M_PI =3.14
0度 對應是圓的最右側點
clockwise 順時針 0 或者逆時針 1
CGContextAddArc(context, 100, 100, 100, 0, M_PI_2, 1);
[[UIColor grayColor] setFill];
CGContextDrawPath(context, kCGPathFill);
6、繪制圖像
UIImage *image = [UIImage imageNamed:@"頭像1.png"];
//提示:繪制之后,就無法改變位置,也沒有辦法監聽手勢識別
在指定點繪制圖像
//[image drawAtPoint:CGPointMake(50, 50)];
//會在指定的矩形中拉伸繪制
[image drawInRect:CGRectMake(0, 0, 320, 460)];
//在指定矩形區域中平鋪圖片
[image drawAsPatternInRect:CGRectMake(0, 0, 320, 460)];
7、繪制文字
NSString *string = @"時間到了反饋結束了的開發就流口水的減肥來看就";
//在指定點繪制文字
[string drawAtPoint:CGPointMake(0, 0) withAttributes:@{NSForegroundColorAttributeName:[UIColor redColor]}];
//在指定的矩形區域繪制文字
CGRect rect = CGRectMake(50, 50, 210, 360);
[string drawInRect:rect withAttributes:@{NSForegroundColorAttributeName:[UIColor redColor]}];
提示:如果不在drawRect方法中調用繪圖方法,上下文地址都是0,不能直接進行繪制
8、繪制水印圖片
1. 建立圖像的上下文,需要指定新生成的圖像大小
CGSize imageSize = CGSizeMake(320, 200);
UIGraphicsBeginImageContext(imageSize);
2、繪制圖片
UIImage *image = [UIImage imageNamed:@"NatGeo01.png"];
[image drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
3、繪制矩形
[[UIColor yellowColor]set];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddRect(context, CGRectMake(50, 50, 100, 100));
CGContextDrawPath(context, kCGPathEOFill);
4、添加水印文字
NSString *str = @"我的水印";
[str drawInRect:CGRectMake(0, imageSize.height - 30, imageSize.width - 20, 30)? withAttributes:@{NSForegroundColorAttributeName:[UIColor redColor]}];
5、獲取到新生成的圖像,從當前上下文獲取到新繪制的圖像
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
6、關閉圖像上下文
UIGraphicsEndImageContext();