什么是Quartz 2D
1>Quartz 2D是一個二維繪圖引擎,同時支持iOS和Mac OS X系統(跨平臺,純C語言的),包含在Core Graphics框架中.
2> Quartz 2D的API是純C語言的.數據類型和函數基本都是以CG作為前綴.如: CGContextRef, CGPathRef, CGContextStrokePath……
Quartz 2D能完成什么工作?
l1>繪制圖形:線條,三角形,矩形,圓,弧,等….
l2>繪制文字.
l3>繪制生成圖片(圖像).
l4>讀取\生成PDF.
l5>截圖\裁剪圖片.
l6>自定義UI控件,如環形下載進度條等.
Quartz 2D繪圖主要步驟:
l1>獲取“圖形上下文”.
l2>向“圖形上下文”中添加“路徑”.
l3>渲染.把圖形上下文中的圖形繪制到對應的設備上.
關于圖形上下文CGContextRef中主要包含的信息:
l1>繪圖路徑(各種各樣的圖形).
l2>繪制狀態(顏色,線寬,樣式,旋轉,縮放,平移,圖片裁剪區域等).
l3>輸出目標(繪制到什么地方去?UIView,圖片, pdf,打印機等).
使用Quartz 2D繪圖:
l1>繪圖路徑(各種各樣的圖形).
l2>繪制狀態(顏色,線寬,樣式,旋轉,縮放,平移,圖片裁剪區域等).
l3>輸出目標(繪制到什么地方去??UIView,圖片, pdf,打印機等).
使用方式一直接調用Quartz2D的API進行繪圖
l1>代碼量稍大,功能全面.
l2>步驟如下.
步驟一獲取繪圖上下文
步驟二把圖形繪制到繪圖上下文中
步驟三把繪圖上下文上的圖形渲染到對應的設備上
使用方式二調用UIKit框架封裝好的API進行繪圖
l1>代碼相對簡單,只對部分Quartz2D的API做了封裝.比如:畫圖片,文字到控件上.
l2>對于沒有封裝的功能只能調用Quartz2D原生的API
DrawRect:方法介紹
l1.為什么向UIView上繪圖,代碼必須寫到drawRect:方法中?
原因:因為只有在view的drawRect:方法中,才能正確的獲取這個view的layer的圖形上下文。
l2.drawRect:方法一定不要自己手動去調用。系統會自動在該調用的時候去調用這個方法。
請問:為什么不能手動去調用這個方法?
1>因為系統在調用drawRect:方法之前,會先創建一個和當前view相關的layer的圖形上下文。這樣的話,在drawRect:這個方法中就可以正確的獲取相應的圖形上下文,然后就可以進行繪圖了。
2>如果手動去調用drawRect:方法,那么在調用drawRect:方法的時候,無法保證和當前view相關的layer的圖形上下文已經創建,所以在drawRect:這個方法中就可能無法正確的獲取相應的圖形上下文,如果沒有圖形上下文,那么也就無法進行繪圖。
l3.如果必須需要重繪的話,怎么辦?
解答:如果必須要進行一次重新繪制,那么也不要直接調用drawRect:方法,而是去調用setNeedsDisplay或者setNeedsDisplayInRect:。這兩個方法內部會先創建一個圖形上下文對象,然后調用drawRect:方法。
l4.drawRect:方法是什么時候調用的?調用幾次?
1>這個方法只在第一次顯示view的時候調用一次
2>如果后續需要重新刷新這個view的顯示,那么需要調用setNeedsDisplay或者setNeedsDisplayInRect:
3>或者是當前view進行重新繪制的時候就會調用drawRect:方法
l5.drawRect:方法中的參數rect指的是什么?
解答:當前繪圖view的bounds。
l6.補充和注意點:
1> UIView內部有個layer(圖層)屬性,drawRect:方法中取得的是一個Layer Graphics Context,因此,繪制的東西其實是繪制到view的layer上去了.
2> UIView之所以能顯示東西,完全是因為它內部的layer.
l7.UIView主要的兩個功能是什么?
1>顯示,為什么UIView可以顯示內容,原因是UIView內部有一個layer,也就是說我們實際上向UIView中繪制的所有內容,其實最終都是畫在了layer上.
2>監聽事件.
案例一Quartz2D簡單演練
展示效果:
請問:實現的步驟是什么?
第一步,在控制器的界面中拖入一個UIView控件,并將類型更改為自定義的類型,重寫drawRect:方法進行繪圖,此時繪制的圖形會被渲染到控件的layer圖層上.
第二步,繪制線條和三角形,使用Quartz 2D原生API來進行繪圖.請問:有哪3個步驟?.
1>獲得圖形上下文
2>拼接路徑
3>渲染
第三步,使用UIKit框架封裝好的UIBezierPath對象來進行繪制圖形.請問:有哪幾個步驟?.
1>獲得圖形上下文
2>創建一個UIBezierPath對象(路徑對象)
3>向UIBezierPath對象中添加若干個路徑
4>把UIBezierPath添加到對應的圖形上下文中
5>渲染
第四步,繪制矩形框.
//代碼實現使用Quartz2D原生API來進行繪圖
------------------------------HMDrawingView.m------------------------------
//
Only override drawRect: if you perform custom drawing.An empty implementation
adversely affects performance during animation.
//僅僅只應該在自定義繪圖的時候重寫drawRect:該方法.如果僅僅重寫該方法,而不執行任何代碼,那么在執行動畫期間會產生一些不利的影響.
```
- (void)drawRect:(CGRect)rect {
// 1.獲取圖形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
/**********路徑信息**********/
// 2.向圖形上下文中添加路徑-繪制一個三角形
// 2.1移動到一個起始點
CGContextMoveToPoint(ctx,50,50);
// 2.2添加一條線到某個點
CGContextAddLineToPoint(ctx,150,50);
// 2.3再添加一條線段
CGContextAddLineToPoint(ctx,50,200);
// 2.4再添加一條線段
//CGContextAddLineToPoint(ctx, 50, 50);
// 2.5關閉路徑
CGContextClosePath(ctx);
//在添加一個新的線段
// 2.6移動到一個新的起點-繪制一條線
CGContextMoveToPoint(ctx,50,260);
// 2.7添加一條線段
CGContextAddLineToPoint(ctx,260,260);
/**********狀態信息**********/
//設置線條的狀態
CGContextSetLineWidth(ctx,20);
//設置線頭樣式
CGContextSetLineCap(ctx,kCGLineCapRound);
//線段連接處的樣式
CGContextSetLineJoin(ctx,kCGLineJoinRound);
//設置線條的顏色
[[UIColorredColor]setStroke];//空心
[[UIColoryellowColor]setFill];//實心
//設置stroke & fill顏色
[[UIColorblueColor]set];
// 3.渲染
CGContextStrokePath(ctx);//空心渲染
CGContextFillPath(ctx);//實心渲染
}
```
//代碼實現使用UIKit框架封裝好的UIBezierPath對象來進行繪制圖形
------------------------------HMDrawingView.m------------------------------
```
- (void)drawRect:(CGRect)rect {
// 1.獲取圖形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.創建一個UIBezierPath對象(路徑對象)
UIBezierPath*path = [UIBezierPathbezierPath];
// 3.向UIBezierPath對象中添加若干個路徑
[pathmoveToPoint:CGPointMake(50,50)];
[pathaddLineToPoint:CGPointMake(150,50)];
[pathaddLineToPoint:CGPointMake(50,150)];
[pathclosePath];
// 4.把UIBezierPath添加到對應的圖形上下文中
CGContextAddPath(ctx, path.CGPath);
// 5.渲染
CGContextStrokePath(ctx);
}
//步驟四繪制“矩形框”使用Quartz 2D原生API來進行繪圖
- (void)drawRect:(CGRect)rect {
// 1.獲取圖形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.繪制矩形框
CGContextAddRect(ctx,CGRectMake(50,50,100,100));
// 3.渲染
CGContextStrokePath(ctx);
}
//步驟四使用UIKit框架封裝好的UIBezierPath對象來進行繪制圖形
- (void)drawRect:(CGRect)rect {
// 1.獲取圖形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.創建路徑對象
UIBezierPath*path = [UIBezierPathbezierPathWithRect:CGRectMake(50,50,100,100)];
// 3.把路徑添加到上下文中
CGContextAddPath(ctx, path.CGPath);
// 4.渲染
CGContextStrokePath(ctx);
}
```
//其它演練–核心代碼
//繪制圓角矩形框
UIBezierPath*path =
[UIBezierPathbezierPathWithRoundedRect:CGRectMake(50,50,150,150)cornerRadius:20];//如果這里的圓角半徑寫成寬度高度的一半,那么就是一個圓
//繪制一個圓形
UIBezierPath*path =
[UIBezierPathbezierPathWithOvalInRect:CGRectMake(50,50,150,150)];
//繪制扇形
1> center :圓心
2> redius :半徑
3> startAngle :起始角度
4> endAngle :結束角度
5> clockwise : YES ->順時針旋轉NO ->逆時針旋轉
UIBezierPath*path =
[UIBezierPathbezierPathWithArcCenter:CGPointMake(150,150)radius:100startAngle:0endAngle:M_PIclockwise:YES];
Even-Odd
rule :奇偶填充規則
當一個點被覆蓋過奇數次則“填充”,偶數次則“不填充”.
```
//代碼實現
- (void)drawRect:(CGRect)rect {
// 1.獲取圖形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.繪制路徑
UIBezierPath*path1 = [UIBezierPathbezierPathWithRect:CGRectMake(250,30,20,200)];
UIBezierPath*path2 = [UIBezierPathbezierPathWithArcCenter:CGPointMake(200,150)radius:80startAngle:0endAngle:M_PI*2clockwise:YES];
UIBezierPath*path3 = [UIBezierPathbezierPathWithRect:CGRectMake(100,100,200,100)];
// 3.添加路徑
CGContextAddPath(ctx, path1.CGPath);
CGContextAddPath(ctx, path2.CGPath);
CGContextAddPath(ctx, path3.CGPath);
// 4.渲染
//說明:被覆蓋過奇數次數的點填充,被覆蓋過偶數次的點不填充
CGContextDrawPath(ctx,kCGPathEOFill);
}
```
nonzero
winding number rule :非零繞數規則
當一個點被從左到右覆蓋過標記為1,從右到左覆蓋過標記為-1,當標記為0的時候不填充,其它則填充.簡單總結,這個規則與方向有關,與次數無關.
//代碼實現
```
- (void)drawRect:(CGRect)rect
{
// 1.獲取圖形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.繪制路徑
UIBezierPath*path1 = [UIBezierPathbezierPathWithArcCenter:CGPointMake(150,150)radius:100startAngle:0endAngle:M_PI*2clockwise:YES];
UIBezierPath*path2 = [UIBezierPathbezierPathWithArcCenter:CGPointMake(150,150)radius:50startAngle:0endAngle:M_PI*2clockwise:NO];
// 3.添加路徑
CGContextAddPath(ctx,
path1.CGPath);
CGContextAddPath(ctx, path2.CGPath);
// 4.渲染
CGContextDrawPath(ctx,kCGPathFill);
}
```