移動開發(IOS) – Quartz 2D繪圖

移動開發(IOS) – Quartz 2D繪圖

By docoder in 博客學習 on 2014/07/02

Quartz-2D

1.Quartz 2D

1.1.Quartz 2D是一個二維圖形繪製引擎,支持iOS環境和Mac OS X環境。

1.2.Quartz 2D API可以實現許多功能,如基於路徑的繪圖、透明度、陰影、顏色管理、反鋸齒、PDF文檔生成和PDF元數據訪問等。

1.3.Quartz 2D API是Core Graphics框架的一部分,因此其中的很多數據類型和方法都是以CG開頭的。會經常見到Quartz 2D(Quartz)和Core Graphics兩個術語交互使用。

1.4.Quartz 2D與分辨率和設備無關,因此在使用Quartz 2D繪圖時,無需考慮最終繪圖的目標設備。

1.5.Quartz中默認的座標系統是:原點(0, 0)在左下角。沿着X軸從左到右座標值逐漸增大;沿着Y軸從下到上座標值逐漸增大。

1.6.座標系的轉換:

CGContextRotateCTM(CGContextRef c, CGFloat angle) 相對原點旋轉上下文座標系
CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty) 相對原點平移上下文座標系
CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy) 縮放上下文座標系

1.6.1.轉換座標系前,使用 CGContextSaveGState(CGContextRef c) 保存當前上下文狀態
1.6.2.座標系轉換後,使用 CGContextRestoreGState(CGContextRef c) 可以恢復之前保存的上下文狀態

1.7.Quartz 2D的繪圖是有順序的,後面畫的可以覆蓋前面畫的。

2.Core Graphics

2.1.Core Graphic 框架是一組基於 C 的 API,當使用 UIKit 創建按鈕、標籤或者其他 UIView 的子類時,UIKit 會用 Core Graphics 將這些元素繪製在屏幕上。此外,UIEvent ( UIKit 中的事件處理類)也會使用 Core Graphics,用來幫助確定觸摸事件在屏幕上所處的位置。

2.2.因爲 UIKit 依賴於 Core Graphics,所以當引入 <UIKit/Uikit.h> 時,Core Graphics 框架會被自動引入,即 UIKit 內部已經引入了 Core Graphics 框架的主頭文件: <CoreGraphics/CoreGraphics.h>。

2.3.UIKit 內部封裝了 Core Graphics 的一些 API,可以快速生成通用的界面元素。

3.Graphics Context

3.1.Graphics Context 是一個數據類型 ( CGContextRef ),封裝了 Quartz 繪製圖像到輸出設備的信息。輸出設備可以是 PDF 文件、 Bitmap 或者顯示器的窗口。

3.2.Quartz 中所有的對象都是繪製到一個 Graphics Context 中。

3.3.當用 Quartz 繪圖時,所有設備相關的特性都包含在 Graphics Context 中。換句話說,我們可以簡單地給Quartz 繪圖序列指定不同的 Graphics Context,就可將相同的圖像繪製到不同的設備上。而不需要任何設備相關的計算,這些都由 Quartz 替我們完成。

3.4.Quartz 提供了以下幾種類型的 Graphics Context:

3.4.1.Bitmap Graphics Context

3.4.2.PDF Graphics Context

3.4.3.Window Graphics Context

3.4.4.Layer Graphics Context

3.4.6.Printer Graphics Context

3.5.一個 Graphics Context 表示一個繪製目標。它包含繪製系統用於完成繪製指令的繪製參數和設備相關信息。

3.6.Graphics Context 定義了基本的繪製屬性,如顏色、裁減區域、線條寬度和樣式信息、字體信息、混合模式等。

3.7.在 iOS 應用程序中,如果要在屏幕上進行繪製,需要創建一個 UIView 對象,並實現它的 drawRect: 方法。視圖的 drawRect: 方法在視圖顯示在屏幕上及它的內容需要更新時被調用。

3.8.在調用自定義的 drawRect: 後,視圖對象自動配置繪圖環境以便能立即執行繪圖操作。

3.9.作爲配置的一部分,視圖對象將爲當前的繪圖環境創建一個 Graphics Context 。通過調用 UIGraphicsGetCurrentContext() 方法可以獲取當前的 Graphics Context。

3.10.UIView 中的 UIGraphicsGetCurrentContext 方法返回的圖形上下文的座標系統的原點位於左上角,而沿着 Y 軸從上到下座標值逐漸增大。於是,在繪圖時無需進行座標轉換。

4.利用 Quartz 2D 繪製 UIView

4.1.當在 UIView 子類中重寫 drawRect: 方法時,iOS 會自動準備好一個圖形上下文,可以通過調用 UIGraphicsGetCurrentContext() 來獲取。

4.2.只要一個 UIView 需要被刷新或者重繪,drawRect: 方法就會被調用,所以 drawRect: 的調用頻率很高。

4.3.重繪時應該調用 setNeedsDisplay ,而不能直接調用 drawRect:, setNeedsDisplay 會自動調用 drawRect: 。

4.4.drawRect: 注意事項:

4.4.1.drawRect: 是在 UIViewController 的 loadView 和 viewDidLoad 兩方法之後調用的。

4.4.2.如果在 UIView 初始化時沒有設置 CGRect,drawRect: 將不會被自動調用。

4.4.3.如果設置 UIView 的 contentMode 屬性值爲 UIViewContentModeRedraw,那麼將在每次更改 frame 時自動調用 drawRect: 。

4.4.4.如果使用 UIView 繪圖,只能在 drawRect: 方法中獲取相應的 CGContextRef 並繪圖。而在其他方法中獲取的 CGContextRef 不能用於繪圖。

5.Quartz內存管理

5.1.使用含有 “Create” 或 “Copy” 的函數創建的對象,使用完後必須釋放,否則將導致內存泄露。使用不含有“Create”或“Copy”的函數獲取的對象,則不需要釋放。

5.2.如果 retain 了一個對象,不再使用時,需要將其 release 掉。可以使用 Quartz 2D 的函數來指定 retain 和 release 一個對象。例如,如果創建了一個 CGColorSpace 對象,則使用函數 CGColorSpaceRetain 和 CGColorSpaceRelease 來 retain 和 release 對象。也可以使用 Core Foundation 的 CFRetain 和 CFRelease 。注意不能傳遞 NULL 值給這些函數。

6.基本繪圖

6.1.繪製直線

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 1. 獲取上下文(UIView對應的上下文)
CGContextRef context = UIGraphicsGetCurrentContext();//使用Ref聲明的對象,不需要用*
// 2. 創建可變的路徑並設置路徑 (當我們開發動畫的時候,通常需要指定對象運動的路線,然後由動畫方法負責實現動畫效果)
CGMutablePathRef path = CGPathCreateMutable();
// 畫線
// 1) 設置起始點
CGPathMoveToPoint(path, NULL, 50, 50);
// 2) 設置目標點
CGPathAddLineToPoint(path, NULL, 200, 200);
CGPathAddLineToPoint(path, NULL, 50, 200);
// 3) 封閉路徑
// a) 直接指定目標點
CGPathAddLineToPoint(path, NULL, 50, 50);
// b) 使用關閉路徑方法
CGPathCloseSubpath(path);
// 3. 將路徑添加到上下文
CGContextAddPath(context, path);
// 4. 設置上下文屬性
//在使用rgb顏色設置時,最好不要同時指定 rgb 和 alpha,否則會對性能造成一定影響
//默認線條和填充顏色都是黑色
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 1.0);
// 設置線條寬度
CGContextSetLineWidth(context, 5.0);
// 設置線條的頂點樣式
CGContextSetLineCap(context, kCGLineCapRound);
// 設置線條的連接點樣式
CGContextSetLineJoin(context, kCGLineJoinRound);
// 設置線條的虛線樣式
/*
 * 虛線的參數
 * context 上下文對象
 * phase 相位,虛線起始的位置,通常使用0即可,從頭開始畫虛線
 * lengths 長度的數組
 * count lengths數組的個數
 */
CGFloat lengths[2] = {20.0, 10.0};
CGContextSetLineDash(context, 0.0, lengths, 2);
// 5. 繪製路徑
/*
 * kCGPathStroke: 畫線(空心)
 * kCGPathFill: 填充(實心)
 * kCGPathFillStroke: 即畫線又填充
 */
CGContextDrawPath(context, kCGPathFillStroke);
// 6. 釋放路徑
CGPathRelease(path);

使用默認的 context 進行繪製直線:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 1. 獲取上下文
CGContextRef context = UIGraphicsGetCurrentContext();
// 2. 設置當前上下文的路徑
// 1) 設置起始點
CGContextMoveToPoint(context, 50, 50);
// 2) 增加點
CGContextAddLineToPoint(context, 200, 200);
CGContextAddLineToPoint(context, 50, 200);
// 3) 關閉路徑
CGContextClosePath(context);
// 3 設置屬性
/*
 * UIKit默認會導入Core Graphics框架,UIKit對常用的很多CG方法做了封裝
 * UIColor setStroke 設置邊線顏色
 * UIColor setFill 設置填充顏色
 * UIColor set 設置邊線和填充顏色
 */
// 設置邊線
// [[UIColor redColor]setStroke];
// 設置填充
// [[UIColor blueColor]setFill];
// 設置邊線和填充
[[UIColor greenColor]set];
// 4 繪製路徑,雖然沒有直接定義路徑,但是第2步操作,就是爲上下文指定路徑
CGContextDrawPath(context, kCGPathFillStroke);

6.2.繪製矩形

1
2
3
4
5
6
CGRect rect = CGRectMake(50, 50, 200.0, 200.0);
[[UIColor redColor]set];
// 繪製實心矩形
UIRectFill(rect);
// 繪製空心矩形
UIRectFrame(CGRectMake(50, 300, 100, 100));

6.3.繪製圓形

1
2
3
4
5
6
7
8
// 1. 取出上下文
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(50, 50, 200, 100);
// 2. 設置路徑
UIRectFrame(rect);
CGContextAddEllipseInRect(context, rect);
// 3. 繪製路徑
CGContextDrawPath(context, kCGPathFillStroke);

6.4.繪製圓弧

1
2
3
4
5
6
7
8
9
10
11
12
// 1. 設置路徑
/*
 * CGContextAddArc(context, x, y, radius, startAngle, endAngle, clockwise);
 * context 上下文
 * x,y 是圓弧所在圓的中心點座標
 * radius 半徑,所在圓的半徑
 * startAngle endAngle 起始角度和截止角度 單位是弧度
 * clockwise 順時針 0 或者逆時針 1
 */
CGContextAddArc(context, 160, 230, 100, -M_PI_4, M_PI_4, 0);
// 2. 繪製圓弧
CGContextDrawPath(context, kCGPathFill);

6.5.繪製文字

1
2
3
4
5
6
7
8
9
10
11
NSString *string = @"Hello world";
// 獲取字體 ( [UIFont familyNames] )
UIFont *font = [UIFont fontWithName:@"Marker Felt" size:20];
// 在指定點繪製字符串
[string drawAtPoint:CGPointMake(50, 50) withFont:font];
// 如果在UILabel中,可以將numbersOfLine設置爲0,並且指定足夠的高度即可
CGRect rect = CGRectMake(50, 50, 210, 360);
[[UIColor lightGrayColor]set];
UIRectFill(rect);
[[UIColor redColor]set];
[string drawInRect:rect withFont:font lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentCenter];

6.6.繪製圖像

1
2
3
4
5
6
7
8
UIImage *image = [UIImage imageNamed:@"image.png"];
// 繪製之後,就無法改變位置,也沒有辦法監聽手勢識別
// 在指定點繪製圖像
[image drawAtPoint:CGPointMake(50, 50)];
// 會在指定的矩形中拉伸繪製
[image drawInRect:CGRectMake(0, 0, 320, 460)];
// 在指定矩形區域中平鋪圖片
[image drawAsPatternInRect:CGRectMake(0, 0, 320, 460)];

7.繪製漸變

7.1.徑向漸變

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1. 創建顏色空間
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// 2. 創建漸變
/*
 * colorSpace 顏色空間 RGB
 * components 數組,每4個一組,表示一個顏色 {r, g, b, a, r, g, b, a}
 * locations 表示漸變開始的位置
 */
CGFloat components[8] = {1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0};
CGFloat locations[2] = {0.3, 1.0};
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
// 漸變的區域剪裁 (整個漸變實際上是完整繪製在屏幕上的,通過裁剪區域,可以讓指定範圍內顯示漸變效果)
// 3. 設置裁剪區域範圍
// 4. 繪製漸變
/*
 * context 上下文
 * gradient 漸變
 * startCenter 起始中心點
 * startRadius 起始半徑,如果指定爲0,就從圓心開始漸變,否則,會空出指定半徑的位置,不填充
 * endCenter 截止點(通常和起始中心點重合,即便偏移,也不會太大)
 * endRadius 截止半徑
 * 漸變填充方式
 */
CGContextDrawRadialGradient(context, gradient, CGPointMake(160, 230), 10, CGPointMake(0, 0), 150, kCGGradientDrawsAfterEndLocation);
// 5. 釋放對象
CGColorSpaceRelease(colorSpace);
CGGradientRelease(gradient);

7.2.線性漸變

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 1. 創建顏色空間
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// 2. 創建漸變
/*
 * colorSpace 顏色空間 rgb
 * components 數組,每4個一組,表示一個顏色 {r, g, b, a, r, g, b, a}
 * location 表示漸變開始的位置
 */
CGFloat components[8] = {1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0};
CGFloat locations[2] = {0.0, 1.0};
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
// 漸變的區域剪裁 (整個漸變實際上是完整繪製在屏幕上的,通過裁剪區域,可以讓指定範圍內顯示漸變效果)
CGContextClipToRect(context, CGRectMake(0, 360, 200, 100));
// 3. 設置裁剪區域範圍
CGRect rects[5] = {CGRectMake(0, 0, 100, 100),
CGRectMake(200, 0, 100, 100),
CGRectMake(100, 100, 100, 100),
CGRectMake(200, 200, 100, 100),
CGRectMake(0, 200, 100, 100)};
CGContextClipToRects(context, rects, 5);
// 4. 繪製漸變
CGContextDrawLinearGradient(context, gradient, CGPointMake(0.0, 0.0), CGPointMake(320.0, 460.0), kCGGradientDrawsAfterEndLocation);
// 5. 釋放對象
CGColorSpaceRelease(colorSpace);
CGGradientRelease(gradient);

8.生成PDF文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1. 創建PDF上下文
/*
 * path 保存 PDF 文件的路徑
 * bounds 大小如果指定 CGRectZero,則建立612 * 792大小的頁面
 * documentInfo 文檔信息
 */
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [array[0] stringByAppendingPathComponent:@"test.pdf"];
UIGraphicsBeginPDFContextToFile(path, CGRectZero, NULL);
// 2. 創建PDF內容
/*
 * PDF 中是分頁的,要一個頁面一個頁面的創建
 * 使用 UIGraphicsBeginPDFPage 方法可以創建一個 PDF 的頁面
 */
for (NSInteger i = 0; i < 6; i++) {
    // 1) 創建PDF頁面,每個頁面的裝載量是有限的
    if (i % 2 == 0) {
        UIGraphicsBeginPDFPage();
    }
    // 2) 將Image添加到PDF文件 (一個頁面裝2張圖片)
    NSString *fileName = [NSString stringWithFormat:@"NatGeo%02d.png", i + 1];
    UIImage *image = [UIImage imageNamed:fileName];
    [image drawInRect:CGRectMake(0, (i % 2) * 396, 612, 396)];
 }
 
// 3. 關閉PDF上下文
UIGraphicsEndPDFContext();

9.Quantz 2D 基本繪圖方法

函數 方法
CGContextBeginPath 開始一個新路徑
CGContextMoveToPoint 設置路徑的起點
CGContextClosePath 關閉路徑
CGContextAddPath 添加路徑
CGContextAddLineToPoint 在指定點添加線
CGContextAddLines 添加多條線
CGContextAddRect 添加矩形
CGContextAddRects 添加多個矩形
CGContextAddEllipseInRect 在矩形區域中添加橢圓
CGContextAddArc 添加圓弧
CGContextAddArcToPoint 在指定點添加圓弧
CGContextAddCurveToPoint 在指定點添加曲線
CGContextDrawPath 繪製路徑
CGContextFillPath 實心路徑
CGContextFillRect 實心矩形
CGContextFillRects 多個實心矩形
CGContextFillEllipseInRect 在矩形區域中繪製實心橢圓
CGContextStrokePath 空心路徑
CGContextStrokeRect 空心矩形
CGContextStrokeRectWithWidth 使用寬度繪製空心矩形
CGContextStrokeEllipseInRect 在矩形區域中繪製空心橢圓
CGContextSetLineWidth 設置線寬
CGContextSetBlendMode 設置混合模式
CGContextSetShouldAntialias 設置抗鋸齒效果
CGContextSetLineCap 設置線條收尾點樣式
CGContextSetLineJoin 設置線條連接點樣式
CGContextSetLineDash 設置虛線

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章