學(xué)習(xí)繪圖教程的總結(jié)
使用框架:Core Graphics FrameWork
iOS支持兩套圖形API族:Core Graphics/QuartZ 2D 和OpenGL ES。
OpenGL ES是跨平臺的圖形API,屬于OpenGL的一個簡化版本。QuartZ 2D是蘋果公司開發(fā)的一套API,它是Core Graphics Framework的一部分。
注意點:
1、Core Graphics API 操作都在上下文中進行。圖形上下文理解為一快畫布。
2、所有繪圖操作結(jié)束后需要關(guān)閉圖形上下文。
3、使用UIKit只能在當(dāng)前上下文中進行。
4、UIGraphicsPushContext
將context轉(zhuǎn)化為當(dāng)前上下文
UIGraphicsPopContext
5、UIGraphicsBeginImageContextWithOptions 創(chuàng)建的上下文就是當(dāng)前上下文
6、
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100),?NO,?0);
UIGraphicsBeginImageContextWithOptions函數(shù)參數(shù)的含義:第一個參數(shù)表示所要創(chuàng)建的圖片的尺寸;第二個參數(shù)用來指定所生成圖片的背景是否為不透明,如上我們使用YES而不是NO,則我們得到的圖片背景將會是黑色,顯然這不是我想要的;第三個參數(shù)指定生成圖片的縮放因子,這個縮放因子與UIImage的scale屬性所指的含義是一致的。傳入0則表示讓圖片的縮放因子根據(jù)屏幕的分辨率而變化,所以我們得到的圖片不管是在單分辨率還是視網(wǎng)膜屏上看起來都會很好。
許多的屬性組成了一個圖形上下文狀態(tài),這些屬性設(shè)置決定了在你繪圖時圖形的外觀和行為。下面我列出了一些屬性和對應(yīng)修改屬性的函數(shù);雖然這些函數(shù)是關(guān)于Core Graphics的,但記住,實際上UIKit同樣是調(diào)用這些函數(shù)操縱上下文狀態(tài)。
線條的寬度和線條的虛線樣式
CGContextSetLineWidth、CGContextSetLineDash
線帽和線條聯(lián)接點樣式
CGContextSetLineCap、CGContextSetLineJoin、CGContextSetMiterLimit
線條顏色和線條模式
CGContextSetRGBStrokeColor、CGContextSetGrayStrokeColor、CGContextSetStrokeColorWithColor、CGContextSetStrokePattern
填充顏色和模式
CGContextSetRGBFillColor,CGContextSetGrayFillColor,CGContextSetFillColorWithColor, CGContextSetFillPattern
陰影
CGContextSetShadow、CGContextSetShadowWithColor
混合模式
CGContextSetBlendMode(決定你當(dāng)前繪制的圖形與已經(jīng)存在的圖形如何被合成)
整體透明度
CGContextSetAlpha(個別顏色也具有alpha成分)
文本屬性
CGContextSelectFont、CGContextSetFont、CGContextSetFontSize、CGContextSetTextDrawingMode、CGContextSetCharacterSpacing
是否開啟反鋸齒和字體平滑
CGContextSetShouldAntialias、CGContextSetShouldSmoothFonts
另外一些屬性設(shè)置:
裁剪區(qū)域:在裁剪區(qū)域外繪圖不會被實際的畫出來。
變換(或稱為“CTM“,意為當(dāng)前變換矩陣): 改變你隨后指定的繪圖命令中的點如何被映射到畫布的物理空間。
許多這些屬性設(shè)置接下來我都會舉例說明。
路徑與繪圖
通過編寫移動虛擬畫筆的代碼描畫一段路徑,這樣的路徑并不構(gòu)成一個圖形。繪制路徑意味著對路徑描邊或填充該路徑,也或者兩者都做。同樣,你應(yīng)該從某些繪圖程序中得到過相似的體會。
一段路徑是由點到點的描畫構(gòu)成。想象一下繪圖系統(tǒng)是你手里的一只畫筆,你首先必須要設(shè)置畫筆當(dāng)前所處的位置,然后給出一系列命令告訴畫筆如何描畫隨后的每段路徑。每一段新增的路徑開始于當(dāng)前點,當(dāng)完成一條路徑的描畫,路徑的終點就變成了當(dāng)前點。
下面列出了一些路徑描畫的命令:
定位當(dāng)前點
CGContextMoveToPoint
描畫一條線
CGContextAddLineToPoint、CGContextAddLines
描畫一個矩形
CGContextAddRect、CGContextAddRects
描畫一個橢圓或圓形
CGContextAddEllipseInRect
描畫一段圓弧
CGContextAddArcToPoint、CGContextAddArc
通過一到兩個控制點描畫一段貝賽爾曲線
CGContextAddQuadCurveToPoint、CGContextAddCurveToPoint
關(guān)閉當(dāng)前路徑
CGContextClosePath 這將從路徑的終點到起點追加一條線。如果你打算填充一段路徑,那么就不需要使用該命令,因為該命令會被自動調(diào)用。
描邊或填充當(dāng)前路徑
CGContextStrokePath、CGContextFillPath、CGContextEOFillPath、CGContextDrawPath。對當(dāng)前路徑描邊或填充會清除掉路徑。如果你只想使用一條命令完成描邊和填充任務(wù),可以使用CGContextDrawPath命令,因為如果你只是使用CGContextStrokePath對路徑描邊,路徑就會被清除掉,你就不能再對它進行填充了。
創(chuàng)建路徑并描邊路徑或填充路徑只需一條命令就可完成的函數(shù):CGContextStrokeLineSegments、CGContextStrokeRect、CGContextStrokeRectWithWidth、CGContextFillRect、CGContextFillRects、CGContextStrokeEllipseInRect、CGContextFillEllipseInRect。
一段路徑是被合成的,意思是它是由多條獨立的路徑組成。舉個例子,一條單獨的路徑可能由兩個獨立的閉合形狀組成:一個矩形和一個圓形。當(dāng)你在構(gòu)造一條路徑的中間過程(意思是在描畫了一條路徑后沒有調(diào)用描邊或填充命令,或調(diào)用CGContextBeginPath函數(shù)來清除路徑)調(diào)用CGContextMoveToPoint函數(shù),就像是你拾起畫筆,并將畫筆移動到一個新的位置,如此來準(zhǔn)備開始一段獨立的相同路徑。如果你擔(dān)心當(dāng)你開始描畫一條路徑的時候,已經(jīng)存在的路徑和新的路徑會被認為是已存在路徑的一個合成部分,你可以調(diào)用CGContextBeginPath函數(shù)指定你繪制的路徑是一條獨立的路徑;蘋果的許多例子都是這樣做的,但在實際開發(fā)中我發(fā)現(xiàn)這是非必要的。
CGContextClearRect函數(shù)的功能是擦除一個區(qū)域。這個函數(shù)會擦除一個矩形內(nèi)的所有已存在的繪圖;并對該區(qū)域執(zhí)行裁剪。結(jié)果像是打了一個貫穿所有已存在繪圖的孔。
CGContextClearRect函數(shù)的行為依賴于上下文是透明還是不透明。當(dāng)在圖形上下文中繪圖時,這會尤為明顯和直觀。如果圖片上下文是透明的(UIGraphicsBeginImageContextWithOptions第二個參數(shù)為NO),那么CGContextClearRect函數(shù)執(zhí)行擦除后的顏色為透明,反之則為黑色。
當(dāng)在一個視圖中直接繪圖(使用drawRect:或drawLayer:inContext:方法),如果視圖的背景顏色為nil或顏色哪怕有一點點透明度,那么CGContextClearRect的矩形區(qū)域?qū)@示為透明的,打出的孔將穿過視圖包括它的背景顏色。如果背景顏色完全不透明,那么CGContextClearRect函數(shù)的結(jié)果將會是黑色。這是因為視圖的背景顏色決定了是否視圖的圖形上下文是透明的還是不透明的。
如圖5,在左邊的藍色正方形被挖去部分留為黑色,然而在右邊的藍色正方形也被挖去部分留為透明。但這兩個正方形都是UIView子類的實例,采用相同的繪圖代碼!不同之處在于視圖的背景顏色,左邊的正方形的背景顏色在nib文件中
獲取上下文方法:
1、第一種方法就是創(chuàng)建一個圖片類型的上下文。調(diào)用UIGraphicsBeginImageContextWithOptions函數(shù)就可獲得用來處理圖片的圖形上下文。利用該上下文,你就可以在其上進行繪圖,并生成圖片。調(diào)用UIGraphicsGetImageFromCurrentImageContext函數(shù)可從當(dāng)前上下文中獲取一個UIImage對象。記住在你所有的繪圖操作后別忘了調(diào)用UIGraphicsEndImageContext函數(shù)關(guān)閉圖形上下文。
2、第二種方法是利用cocoa為你生成的圖形上下文。當(dāng)你子類化了一個UIView并實現(xiàn)了自己的drawRect:方法后,一旦drawRect:方法被調(diào)用,Cocoa就會為你創(chuàng)建一個圖形上下文,此時你對圖形上下文的所有繪圖操作都會顯示在UIView上。
判斷一個上下文是否為當(dāng)前圖形上下文需要注意的幾點:
1.UIGraphicsBeginImageContextWithOptions函數(shù)不僅僅是創(chuàng)建了一個適用于圖形操作的上下文,并且該上下文也屬于當(dāng)前上下文。
2.當(dāng)drawRect方法被調(diào)用時,UIView的繪圖上下文屬于當(dāng)前圖形上下文。
3.回調(diào)方法所持有的context:參數(shù)并不會讓任何上下文成為當(dāng)前圖形上下文。此參數(shù)僅僅是對一個圖形上下文的引用罷了。
UIKit
像UIImage、NSString(繪制文本)、UIBezierPath(繪制形狀)、UIColor都知道如何繪制自己。這些類提供了功能有限但使用方便的方法來讓我們完成繪圖任務(wù)。一般情況下,UIKit就是我們所需要的。
使用UiKit,你只能在當(dāng)前上下文中繪圖,所以如果你當(dāng)前處于UIGraphicsBeginImageContextWithOptions函數(shù)或drawRect:方法中,你就可以直接使用UIKit提供的方法進行繪圖。如果你持有一個context:參數(shù),那么使用UIKit提供的方法之前,必須將該上下文參數(shù)轉(zhuǎn)化為當(dāng)前上下文。幸運的是,調(diào)用UIGraphicsPushContext 函數(shù)可以方便的將context:參數(shù)轉(zhuǎn)化為當(dāng)前上下文,記住最后別忘了調(diào)用UIGraphicsPopContext函數(shù)恢復(fù)上下文環(huán)境。
Core Graphics
使用注意:
1、需要指定圖形上下文(CGContextRef)
這是一個繪圖專用的API族,它經(jīng)常被稱為QuartZ或QuartZ 2D。Core Graphics是iOS上所有繪圖功能的基石,包括UIKit。
使用Core Graphics之前需要指定一個用于繪圖的圖形上下文(CGContextRef),這個圖形上下文會在每個繪圖函數(shù)中都會被用到。如果你持有一個圖形上下文context:參數(shù),那么你等同于有了一個圖形上下文,這個上下文也許就是你需要用來繪圖的那個。如果你當(dāng)前處于UIGraphicsBeginImageContextWithOptions函數(shù)或drawRect:方法中,并沒有引用一個上下文。為了使用Core Graphics,你可以調(diào)用UIGraphicsGetCurrentContext函數(shù)獲得當(dāng)前的圖形上下文。
6種繪圖形式:
第一種繪圖形式:在UIView的子類方法drawRect:中繪制一個藍色圓,使用UIKit在Cocoa為我們提供的當(dāng)前上下文中完成繪圖任務(wù)。
-?(void)?drawRect:?(CGRect)?rect?{
UIBezierPath*?p?=?[UIBezierPathbezierPathWithOvalInRect:CGRectMake(0,0,100,100)];
[[UIColor?blueColor]?setFill];
[p?fill];
}
第二種繪圖形式:使用Core Graphics實現(xiàn)繪制藍色圓
-?(void)?drawRect:?(CGRect)?rect?{
CGContextRef?con?=?UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(con,?CGRectMake(0,0,100,100));
CGContextSetFillColorWithColor(con,?[UIColor?blueColor].CGColor);
CGContextFillPath(con);
}
第三種繪圖形式:我將在UIView子類的drawLayer:inContext:方法中實現(xiàn)繪圖任務(wù)
-?(void)drawLayer:(CALayer*)layer?inContext:(CGContextRef)ctx?{
UIGraphicsPushContext(ctx);
UIBezierPath*?p?=?[UIBezierPath?bezierPathWithOvalInRect:CGRectMake(0,0,100,100)];
[[UIColor?blueColor]?setFill];
[p?fill];
UIGraphicsPopContext();
}
第四種繪圖形式:使用Core Graphics在drawLayer:inContext:方法實現(xiàn)同樣操作
-?(void)drawLayer:(CALayer*)lay?inContext:(CGContextRef)con?{
CGContextAddEllipseInRect(con,?CGRectMake(0,0,100,100));
CGContextSetFillColorWithColor(con,?[UIColor?blueColor].CGColor);
CGContextFillPath(con);
}
演示UIGraphicsBeginImageContextWithOptions的用法,并從上下文中生成一個UIImage對象。生成UIImage對象的代碼并不需要等待某些方法被調(diào)用后或在UIView的子類中才能去做。
第五種繪圖形式:使用UIKit實現(xiàn):
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100),?NO,?0);
UIBezierPath*?p?=?[UIBezierPath?bezierPathWithOvalInRect:CGRectMake(0,0,100,100)];
[[UIColor?blueColor]?setFill];
[p?fill];
UIImage*?im?=?UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
第六種繪圖形式:使用Core Graphics實現(xiàn):
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100),?NO,?0);
CGContextRef?con?=?UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(con,?CGRectMake(0,0,100,100));
CGContextSetFillColorWithColor(con,?[UIColor?blueColor].CGColor);
CGContextFillPath(con);
UIImage*?im?=?UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
example:
(1.獲取上下文,注意我們并沒有拿到上下文的 CGContextRef 引用 :
UIGraphicsBeginImageContextWithOptions(CGRectMake(0,0,100,100),?NO,0.0);
(2. 在上下文中進行繪制.
(3.最后生成繪制的圖片
UIImage*image?=UIGraphicsGetImageFromCurrentImageContext();
(4.關(guān)閉上下文
UIGraphicsEndImageContext();
參考資料:
1、http://www.cocoachina.com/industry/20140115/7703.html