最近公司新項目需求要把數(shù)據(jù)圖形化,趁著這個機會,重溫了下Quarts-2D這個強大的跨平臺2D繪圖引擎。
一、Quartz概述
1.Quartz 2D是一個二維的繪圖引擎,支持iOS和Mac OS平臺。
2.功能:可以用來進行基本路徑的繪制、透明度、描影、繪制陰影、透明層、顏色管理、反鋸齒、PDF文檔生成和PDF元數(shù)據(jù)訪問等
二、Quartz操作
1.繪圖順序:Quartz既然是一個繪圖引擎,那么畫畫的先后順序是非常重要的,下圖便展示了它的操作順序,相信大家都很熟悉這幅圖

2.繪制目標:Graphics Context(繪圖上下文)
相信很多人剛開始接觸到這個單詞時跟我一樣一頭霧水,不明白它指的是什么。按照蘋果的官方文檔解釋說,Graphics Context是種數(shù)據(jù)類型(CGContextRef),用于封裝Quartz繪制圖像到輸出設(shè)備的信息。設(shè)備可以是PDF文件、bitmap或者顯示器的窗口上。Graphics Context中的信息包括在Page中的圖像的圖形繪制參數(shù)和設(shè)備相關(guān)的表現(xiàn)形式。Quartz中所有的對象都是繪制到一個Graphics Context中。其實說白了,就是你想在紙上畫畫,Graphics Context就是那張紙,你想在桌子上畫畫,Graphics Context就是那張桌子。只不過Graphics Context還保存了你的畫筆顏色啊,線條大小啊等一些畫圖時的參數(shù)信息。我們畫圖時想要畫在哪個上面,指定相應的Graphics Context的就可以了。Quartz為我們提供了以下幾種類型的Graphics Context

除了Graphics Context這個類型外,Quartz 2D API還定義一些數(shù)據(jù)類型。由于這些API就是Core Graphics框架的一部分,所以這些數(shù)據(jù)類型都是以CG開頭的,像CGPathRef、CGImageRef之類的,具體的可以參考蘋果官方文檔,這里不再贅述。
3.圖形狀態(tài)
Quartz通過修改當前圖形狀態(tài)(current graphics state)來修改繪制操作的結(jié)果。圖形狀態(tài)包含用于繪制程序的參數(shù)。繪制程序根據(jù)這些繪圖狀態(tài)來決定如何渲染結(jié)果。例如,當你調(diào)用設(shè)置填充顏色的函數(shù)時,你將改變存儲在當前繪圖狀態(tài)中的顏色值。
Graphics Context包含一個繪圖狀態(tài)棧。當Quartz創(chuàng)建一個Graphics Context時,棧為空。當保存圖形狀態(tài)時,Quartz將當前圖形狀態(tài)的一個副本壓入棧中。當還原圖形狀態(tài)時,Quartz將棧頂?shù)膱D形狀態(tài)出棧。出棧的狀態(tài)成為當前圖形狀態(tài)。
可使用函數(shù)CGContextSaveGState來保存圖形狀態(tài),CGContextRestoreGState來還原圖形狀態(tài)
可能上面說有一些抽象,下面上代碼
1 - (void)drawRect:(CGRect)rect { 2 3 CGContextRef context = UIGraphicsGetCurrentContext(); 4 5 // 拷貝一份副本,放入繪圖狀態(tài)棧中,這份副本中的繪制信息為空 6 CGContextSaveGState(context); 7 8 // 在當前的上下文中設(shè)置繪制信息并進行繪制渲染 9 CGContextSetLineWidth(context, 3);10 [[UIColor redColor] set];11 CGContextMoveToPoint(context, 0, 0);12 CGContextAddLineToPoint(context, 100, 100);13 CGContextStrokePath(context);14 15 // CGContextRestoreGState()將繪圖上下文棧彈棧,得到上面拷貝的副本并設(shè)置為當前上下文16 CGContextRestoreGState(context);17 // 此時的繪制信息完全在副本中設(shè)置,不會覆蓋上面的參數(shù)18 [[UIColor blackColor] set];19 CGContextMoveToPoint(context, 10, 0);20 CGContextAddLineToPoint(context, 50, 80);21 CGContextStrokePath(context);22 }
而假如我們不保存圖形狀態(tài),每次設(shè)置繪圖信息都在同一個上下文中,便會覆蓋上一次的狀態(tài),最后渲染時只是一種狀態(tài),線的顏色啊,線寬什么的都只是以你最后設(shè)置的為準。代碼如下
1 - (void)drawRect:(CGRect)rect { 2 3 CGContextRef context = UIGraphicsGetCurrentContext(); 4 5 // 拷貝一份副本,放入繪圖狀態(tài)棧中,這份副本中的繪制信息為空 6 CGContextSaveGState(context); 7 8 // 在當前的上下文中設(shè)置繪制信息并進行繪制渲染 9 CGContextSetLineWidth(context, 3);10 [[UIColor redColor] set];11 CGContextMoveToPoint(context, 0, 0);12 CGContextAddLineToPoint(context, 100, 100);13 CGContextStrokePath(context);14 15 //CGContextRestoreGState(context);16 // 此時的繪制信息便會覆蓋上面的參數(shù)17 [[UIColor blackColor] set];
CGContextSetLineWidth(context, 10);
18 CGContextMoveToPoint(context, 10, 0);
19 CGContextAddLineToPoint(context, 50, 80);
20 CGContextStrokePath(context);21 }
注意:并不是當前繪制環(huán)境的所有方面都是圖形狀態(tài)的元素。如,圖形狀態(tài)不包含當前路徑(current path)。下面列出了圖形狀態(tài)相關(guān)的參數(shù):
4.坐標系統(tǒng)
和我們的UIKit坐標系不同,Quartz是一左下角為原點的,沿著x軸從左到右坐標值逐漸增大;沿著y軸從下到上坐標值逐漸增大。如下圖

由于不同的設(shè)備有不同的圖形功能,所以圖像的位置及大小依賴于設(shè)備。這就意味著,我們必須對其坐標進行相應的映射變換,好在Quartzt通過CTM可以很輕易的辦到這一點。CTM是一種特殊類型的矩陣(affine transform, 仿射矩陣),通過平移(translation)、旋轉(zhuǎn)(rotation)、縮放(scale)操作將點從一個坐標空間映射到另外一個坐標空間。下面上代碼
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); [[UIColor redColor] set]; CGContextRotateCTM(context, M_PI/8);// 讓坐標系順時針旋轉(zhuǎn)M_PI/8 CGContextScaleCTM(context, 1.5, 1.5);// 讓坐標系放大1.5倍 CGContextTranslateCTM(context, 50, 10);// 平移坐標系 CGContextMoveToPoint(context, 0, 0); CGContextAddLineToPoint(context, 100, 100); CGContextAddLineToPoint(context, 40, 80); CGContextAddLineToPoint(context, 0, 0); CGContextStrokePath(context);}
PS:如果你打算在IOS上開發(fā)與Quartz相關(guān)的程序,了解以上所討論的是很有用的,但不是必須的。在IOS 3.2及后續(xù)的版本中,當UIKit為你的應用程序創(chuàng)建一個繪圖上下文時,也對上下文進行了額外的修改以匹配UIKit的約定。特別的,patterns和shadows(不被CTM影響)單獨進行調(diào)整以匹配UIKit坐標系統(tǒng)。在這種情況下,沒有一個等價的機制讓CTM來轉(zhuǎn)換Quartz和UIKit的上下文。我們必須認識到在什么樣的上下文中進行繪制,并調(diào)整行為以匹配上下文的預期。
5.內(nèi)存管理
Quartz使用Core Foundation內(nèi)存管理模型(引用計數(shù))。所以,對象的創(chuàng)建與銷毀與通常的方式是一樣的。在Quartz中,需要記住如下一些規(guī)則:
新聞熱點
疑難解答