Quartz 2D Programming Guide筆記
Graphics Contexts圖形上下文
圖形上下文(graphics context)是繪製目標,可以理解為畫布,包含著繪圖時的引數和裝置資訊。型別為CGContextRef。獲取graphics context後,呼叫Quartz 2D的函式進行繪製、旋轉等操作,還可以修改如線寬、填充顏色等繪畫引數。
獲取圖形上下文
當view出現在螢幕上以及檢視將要更新時,系統會呼叫view的drawRect:方法。我們建立UIView子類,並重寫drawRect:方法,此時呼叫UIKit提供的方法UIGraphicsGetCurrentContext,來獲取系統為我們準備好的當前繪圖環境的graphics context物件,。
路徑
路徑構成一個或多個圖形或子路徑。子路徑可以由直線、曲線或兩者相結合組成。如圖:
點
呼叫CGContextMoveToPoint,傳入表示x和y座標的兩個float值來確定路徑的起始點。
CGContextMoveToPoint(context, 50, 50);
線段
兩個點確定一條線,線的起點為當前點,所以只需要確定終點。
1、呼叫CGContextAddLineToPoint,傳入終點座標來新增一條線。
CGContextAddLineToPoint(context, 100, 50);
2、呼叫CGContextAddLines可以新增多條線,傳入點的陣列,Quartz以第一個點為起點,然後用直線依次連線剩下的點。
GPoint aPoints[3];//座標點
aPoints[0] = CGPointMake(100, 80);//座標1
aPoints[1] = CGPointMake(130, 150);//座標2
aPoints[2] = CGPointMake(130, 200);//座標3
CGContextAddLines(context, aPoints, 3);
【例項1】
Quartz 2D簡單繪製分割線:https://www.jianshu.com/p/52700532f854
弧
弧是圓的一部分,Quartz提供兩個方法來建立弧。
1、CGContextAddArc,傳入圓的中心點座標(x,y)、半徑、起始角度、結束角度、方向(1為時鐘方向)。
CGContextAddArc(context, 100, 100, 50, M_PI_2 , 0, 1);
2、CGContextAddArcToPoint,傳入兩個終點的座標值以及半徑長度,Quartz以兩個終點確定兩條切線,從而確定弧。
【例項2】
可拖動的環形進度:http://blog.csdn.net/dolacmeng/article/details/46617517
曲線
二次和三次貝塞爾曲線可以確定各種各樣的曲線形狀,如圖:
1、呼叫CGContextAddCurveToPoint函式,傳入兩個控制點、結束點,來確定一條三次貝塞爾曲線。
2、通過呼叫CGContextAddQuadCurveToPoint,傳入控制點和結束點,確定一條二次貝塞爾曲線
【例項】貝塞爾曲線動畫demo(仿美人相機效果):http://blog.csdn.net/dolacmeng/article/details/79276039
**例項中使用CAShapeLayer與UIBezierPath結合繪製,而非通過重寫drawRect。UIBezierPath類可以建立基於向量的路徑,這個類在UIKit中,是Core Graphics框架關於path的一個封裝。
CAShapeLayer和drawRect的比較:
- 1.drawRect:屬於CoreGraphics框架,佔用CPU,效能消耗大。
- 2.CAShapeLayer:屬於CoreAnimation框架,通過GPU來渲染圖形,節省效能。動畫渲染直接提交給手機GPU,不消耗記憶體。
參考連結:https://www.jianshu.com/p/b1c38a3a67a9
閉合路徑
呼叫CGContextClosePath,會新增一條從當前點到起始點的線來閉合當前的形狀。
橢圓
橢圓是一個被壓扁的圓形,呼叫CGContextAddEllipseInRect方法,傳入一個用以確定橢圓邊界的矩形。
CGContextAddEllipseInRect(context, CGRectMake(0, 0, 200, 100));
矩形
呼叫CGContextAddRect來新增一個矩形,傳入一個包含原點座標、寬度和高度的CGRect結構體。
CGContextAddRect(context, CGRectMake(0, 0, 200, 100));
可以一次新增多個矩形,只需呼叫CGContextAddRects方法,並傳入CGRect結構體陣列。
CGRect rects[4];
rects[0] = (CGRect){{0,0}, {50, 50}};
rects[1] = (CGRect){{100, 100}, {30, 30}};
rects[2] = (CGRect){{0,100}, {20, 20}};
rects[3] = (CGRect){{100,0}, {10, 10}};
CGContextAddRects(context, rects, 4);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillPath(context);
Creating a Path
建立路徑:
在圖形上下文中建立路徑,先呼叫CGContextBeginPath.然後通過呼叫CGContextMoveToPoint設定起點。之後就繪製新增線、弧或曲線。總之記住:
* 在開始新路徑前,呼叫CGContextBeginPath.
* 線、弧、曲線從當前點開始繪製,所以必須呼叫CGContextMoveToPoint來設定當前起始點或者呼叫對應的便捷方法。
* 當你想要閉合當前路徑,呼叫 CGContextClosePath方法來連線上起始點。
* 當你繪製弧時,Quartz會在當前點和弧的起始點之間繪製一條直線。
* 最後需呼叫繪製函式來填充(fill)或畫(stroke)出路徑。
如:
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 200, 200);
CGContextAddLineToPoint(context, 50, 300);
CGContextClosePath(context);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextStrokePath(context);
當路徑被繪製出來後,路徑會被清除。如果想要儲存路徑,Quartz提供了兩種資料型別來建立可重複利用的路徑:CGPathRef 和 CGMutablePathRef。但操作的是CGPath而不是graphics context:
* CGPathCreateMutable 代替 CGContextBeginPath
* CGPathMoveToPoint 代替 CGContextMoveToPoint
* CGPathAddLineToPoint 代替 CGContextAddLineToPoint
* CGPathAddCurveToPoint 代替 CGContextAddCurveToPoint
* CGPathAddEllipseInRect 代替 CGContextAddEllipseInRect
* CGPathAddArc 代替 CGContextAddArc
* CGPathAddRect 代替 CGContextAddRect
* CGPathCloseSubpath 代替 CGContextClosePath
Painting a Path
Quartz提供方法畫出(畫線)或填充路徑,或者同時畫出(畫線)並填充路徑。繪製的線條特性(寬度、顏色等)、填充顏色和計算填充區域的方式都是graphics state的一部分。
可以通過下表的屬性,修改畫出的路徑特性。一旦修改這些屬性,會作用於之後的所有繪製中。
Parameter | Function to set parameter value |
---|---|
Line width | CGContextSetLineWidth |
Line join | CGContextSetLineJoin |
Line cap | CGContextSetLineCap |
Miter limit | CGContextSetMiterLimit |
Line dash pattern | CGContextSetLineDash |
Stroke color space | CGContextSetStrokeColorSpace |
Stroke color | CGContextSetStrokeColorCGContextSetStrokeColorWithColor |
Stroke pattern | CGContextSetStrokePattern |
line width是線條的寬度,路徑兩邊各佔線寬的一半。
line join表示Quartz怎麼處理線條的連線處。Quartz支援的連線樣式 如下:
line cap表示線的兩個端點的樣式:
line dash線條的樣式:
Quartz提供的畫線方法:
Function | Description |
---|---|
CGContextStrokePath | Strokes the current path. |
CGContextStrokeRect | Strokes the specified rectangle. |
CGContextStrokeRectWithWidth | Strokes the specified rectangle, using the specified line width. |
CGContextStrokeEllipseInRect | Strokes an ellipse that fits inside the specified rectangle. |
CGContextStrokeLineSegments | Strokes a sequence of lines. |
CGContextDrawPath | If you pass the constant kCGPathStroke, strokes the current path. See Filling a Path if you want to both fill and stroke a path. |
Filling a Path
當填充路徑時,Quartz認為每一個路徑都是閉合的,然後利用這些閉合的路徑計算填充區域。一共有兩種計算填充區域的方式。橢圓形、矩形等簡單的路徑,很好確定填充區域。但是如果有重疊的路徑或者路徑內包含多個路徑時(如下圖),有兩種規則來確定填充區域。
預設的填充規則為非零繞組規則:給定一條曲線C和一個點P,構造一條從P點出發射向無窮遠的射線。找出所有該射線和曲線的交點,並按如下規則統計繞組數量(winding number):每一個順時針方向(曲線從左向右通過射線)上的交點減1,每一個逆時針方向(曲線從右向左通過射線)上的交點加1。如果繞組總數為0,表示該點在曲線外;否則,該點在曲線內。
另一個為奇偶規則。平面內的任何一點P,引出一條射線,注意不要經過多邊形的頂點,如果射線與多邊形的交點的個數為奇數,則點P在多邊形的內部,如果交點的個數為偶數,則點P在多邊形的外部。
(參考:http://blog.csdn.net/wodownload2/article/details/52151714)
【例項】中間透明的引導蒙層
http://blog.csdn.net/dolacmeng/article/details/79285679
Quartz提供的填充函式如下3-5:
Function | Description |
---|---|
CGContextEOFillPath | Fills the current path using the even-odd rule. |
CGContextFillPath | Fills the current path using the nonzero winding number rule. |
CGContextFillRect | Fills the area that fits inside the specified rectangle. |
CGContextFillRects | Fills the areas that fits inside the specified rectangles. |
CGContextFillEllipseInRect | Fills an ellipse that fits inside the specified rectangle. |
CGContextDrawPath | Fills the current path if you pass kCGPathFill (nonzero winding number rule) or kCGPathEOFill (even-odd rule). Fills and strokes the current path if you pass kCGPathFillStroke or kCGPathEOFillStroke. |
Setting Blend Modes
重疊模式,兩個繪製重疊時,重疊部分預設的顏色為:
result = (alpha * foreground) + (1 - alpha) * background
Clipping to a Path
路徑可以作為遮罩,進行裁剪。例如有一張大圖,但只希望顯示其中一部分,可以設定裁剪區域,即只顯示在閉合路徑內部的部分:
CGContextBeginPath (context);
CGContextAddArc (context, w/2, h/2, ((w>h) ? h : w)/2, 0, 2*PI, 0);
CGContextClosePath (context);
CGContextClip (context);
提供的裁剪方法:
Function | Description |
---|---|
CGContextClip | Uses the nonzero winding number rule to calculate the intersection of the current path with the current clipping path. |
CGContextEOClip | Uses the even-odd rule to calculate the intersection of the current path with the current clipping path. |
CGContextClipToRect | Sets the clipping area to the area that intersects both the current clipping path and the specified rectangle. |
CGContextClipToRects | Sets the clipping area to the area that intersects both the current clipping path and region within the specified rectangles. |
CGContextClipToMask | Maps a mask into the specif |
Transforms
在繪圖前,可以通過變換矩陣(CTM)進行旋轉、縮放、移動(可以理解為對座標系操作),從而實現對即將繪製的影象進行變換。
下面的程式碼會把一張圖片繪製到上下文:
CGContextDrawImage (myContext, rect, myImage);
呼叫CGContextTranslateCTM函式,改變座標空間原點的x和y,如在x軸上移動100個單位,在y軸上移動50個單位:
CGContextTranslateCTM (myContext, 100, 50);
呼叫CGContextRotateCTM來旋轉座標系。如,旋轉-45度:
CGContextRotateCTM (myContext, radians(–45.));
此時部分圖片內容被裁剪了,因為這部分被移到圖形上下文之外了。另外需要將角度轉換為弧度:
include <math.h>
static inline double radians (double degrees) {return degrees * M_PI/180;}
呼叫CGContextScaleCTM可以在x軸和y軸上對座標系進行縮放,如果為負值,可以進行翻轉。例如在x軸上縮放0.5倍,在y軸上縮放0.75倍:
可以結合使用多個變換,通過CGContextConcatCTM方法可將多個變換組合成一個變換。
也可以直接依次執行多個變換。如:
CGContextTranslateCTM (myContext, w/4, 0);
CGContextScaleCTM (myContext, .25, .5);
CGContextRotateCTM (myContext, radians ( 22.));
Creating Affine Transforms
仿射變換(affine transform)是作用於矩陣而非CTM。可以使用這些函式構造一個矩陣,然後通過函式CGContextConcatCTM應用於CTM。
仿射變換和CTM變換作用相同,都可以進行平移、旋轉、縮放操作。方法和作用如下表:
Function | Use |
---|---|
CGAffineTransformMakeTranslation | To construct a new translation matrix from x and y values that specify how much to move the origin. |
CGAffineTransformTranslate | To apply a translation operation to an existing affine transform. |
CGAffineTransformMakeRotation | To construct a new rotation matrix from a value that specifies in radians how much to rotate the coordinate system. |
CGAffineTransformRotate | To apply a rotation operation to an existing affine transform. |
CGAffineTransformMakeScale | To construct a new scaling matrix from x and y values that specify how much to stretch or shrink coordinates. |
CGAffineTransformScale | To apply a scaling operation to an existing affine transform. |
.
Quartz提供了CGAffineTransformInvert方法來撤消一個矩陣。但一般可以通過儲存和還原graphics state實現類似的需求。
如果想要只對某個點或某部分進行變換,可以通過CGPointApplyAffineTransform方法對點,通過CGSizeApplyAffineTransform對某部分進行操作。
【待續…】