Quartz Core 圖層編程

\

Quartz Core 圖層編程


一、添加 Quartz Core 框架

要使用 Quartz Core 框架,你需要將其添加到你的工程中 。 然後  #import <Quartz Core/QuartzCore.h> 

二、認識圖層

對 ps 有所瞭解的人都知道圖層的概念,在這裏也一樣。在PS中一張圖片至少得有一個圖層,一個或多個圖層的疊加構成了一張位圖。我們這裏一個或多個圖層的疊加的構成了UIView(或其派生類)對象。看過我關於 UIView 文章的人可能會有疑問:UIView 和圖層沒啥區別啊?NO,還是有區別的,圖層是有彈性的,你可以操縱圖層,使 UIView 有各種效果,比如三維效果,形變等等。

要訪問一個圖層,需要讀取 UIview 的 layer 屬性。

[java] view plaincopyprint?

  1. CALayer* layer = self.view.layer;  

所有派生自UIView 的對象,都會繼承這一屬性,這意味着你可以對導航欄、表格、文本框以及其他許多類型的視圖類,進行變換、縮放、旋轉、甚至加入動畫。


有人又有疑問了,上面的代碼我們只讀取了一個 layer 假如一個UIView 有多個圖層呢? 不錯 UIView 確實只有一個layer 屬性,但是layer 是可以疊加的,layer 可以疊加在 layer 上面,所以這個layer 就相當於是一塊底板,我們可以在這塊地板上疊加一些透明膠片(子圖層),疊加在一起之後就構成了一個組合圖像。

三、圖層的層次結構

圖層有很多通用的方法和屬性,來操作子圖層和執行繪製操作。這些方法允許你將許多單個圖層疊加在一起,來繪製一個組合的屏幕圖像。

一個圖層可以有許多個子圖層。在最終繪製屏幕時,子圖層可以被排列後固定在一起。這可以參考×××遊戲中的圖層。遊戲可能有幾個圖層組成:一個繪製背景、一個繪製角色、一個繪製地圖顯示器。你可能會爲每個圖層準備一個專門的UIView類,並另外用一個UIView類來整合遊戲畫面:

[java] view plaincopyprint?

  1. UIView* gameView = [[UIView alloc]initWithFrame:[[UIScreen mainScreen]applicationFrame] ];  

  2.     UIView* backgroundView = [[UIView alloc]initWithFrame:[[UIScreen mainScreen]applicationFrame]];  

  3.     UIView* roleView= [[UIView alloc]initWithFrame:CGRectMake(0.00.0100.0200.0)];  

  4.     UIView* mapView = [[UIView alloc]initWithFrame:CGRectMake(200.00.0100.0100.0)];  

  5.     //通過CALayer 類的addSublayer 方法,你可以將3個UIView 類的圖層全都與 gameView 對象鏈接在一起:  

  6.     CALayer* gameLayer = gameView.layer;  

  7.     [gameLayer addSublayer:backgroundView.layer];  

  8.     [gameLayer addSublayer:roleView.layer];  

  9.     [gameLayer addSublayer:mapView.layer];  

當gameView 對象顯示在屏幕上的時候,3個子圖層被合併在一起繪製出來。每個類單獨繪製他自己的圖層,但當遊戲圖層被顯示出來的時候,3個圖層就全都融合在一起了。

gameView不是唯一能夠添加子圖層的圖層。子圖層也可以添加自己的子圖層,並且可以構建一個完整的圖層層次結構。例如你的遊戲可能會在 mapView圖層中再構加入一個圖層,用來顯示map的一部分內容,比如剩餘里程數。

[java] view plaincopyprint?

  1. UILabel* lastDistance = [[UILabel alloc]initWithFrame:CGRectMake(0.00.020.020.0)];  

  2.     [mapView.layer addSublayer:lastDistance.layer];  

此外,通過設置圖層的position屬性,你還可以不用改變圖層的大小就對其位置進行調整。這個屬性接受一個CGPoint 結構體,來定位圖層在屏幕上的偏移位置。與frame 屬性不同,position 屬性指定的是圖層的重點,而不是左上角:


[java] view plaincopyprint?

  1. CGPoint lastDistancePosition = CGPointMake(100.0100.0);  

  2.   lastDistance.layer.position = lastDistancePosition;  

四、佈局與顯示

除了添加子圖層之外,CALayer 類還提供了很多不同的方法,可以來插入、調整和移除子圖層。

當你用 addSublayer 來添加一個子圖層時,他會被添加到圖層層次結構的頂層,所以他會顯示在現有所有子圖層的最前面。用一組名爲 insertSublayer 的替代方法,你可以將新視圖插入現有的圖層之間。

用atIndex 參數,可以將一個圖層插入到指定的下標位置:

[java] view plaincopyprint?

  1. [gamelayer insertSublayer:mapView.layer atIndex:1];  

要將一個圖層插入到另一個圖層的上面或者下面,可以加上 avove 或 below 參數:

[java] view plaincopyprint?

  1. [ gamelayer insertSublayer:mapView.layer below:backgroundView.layer];  

  2. [ gamelayer insertSublayer:mapView.layer above:roleView.layer];  

調用子圖層的 removeFromSuperlayer 方法,可以將圖層從他的父圖層中刪除:

[java] view plaincopyprint?

  1. [ mapView.layer removeFromSuperlayer];  

要用另外一個圖層代替現有的一個子圖層,可以用replaceSublayer 方法:

[java] view plaincopyprint?

  1. [ gamelayer replaceSublayer:backgroundView.layer with:newBackgroundView.layer ];  

要將子圖層保留在圖層棧中,但是又想讓他在顯示的時候不可見,可以設置圖層的 hidden 屬性。你可以用下面的代碼來切換map 顯示,而不必真的把圖層去掉:

[java] view plaincopyprint?

  1. - (void) Togglemap{  

  2.        mapView.layer.hidden = (mapView.layer.hidden == NO)?YES:NO;  

  3. }  

五、繪製


在更新一個圖層時,變化不是立刻被繪製在屏幕上的。這樣你就可以偷偷地對圖層做很多寫操作而不會被展示給用戶,直到所有的操作全部結束爲止。當圖層準備好可以進行重畫時,就調用圖層的 setNeedsDisplay  方法:

[java] view plaincopyprint?

  1. [ gamelayer setNeedsDisplsy ];  

有些時候,可能僅僅不要重畫整個圖層的部分內容。重新繪製整個屏幕會令程序性能低下。用 setNeedsDisplayInRect 方法,可以只重畫需要更新的部分屏幕,這個方法需要一個表示更新區域的CGRect 結構體作爲參數:

[java] view plaincopyprint?

  1. CGRect mapViewFrame  =CGRectMake(150.0,150,75.0,75.0);  

  2. [ gameLayer setNeedsDisplayInRect:mapViewFrame  ];   

如果你在使用 Core Graphics 框架進行繪製,可以直接在一個 Core Graphics 上下文中繪製。使用 renderInContext 方法可以做到這一點:

[java] view plaincopyprint?

  1. CGContextRef myCGContext = UIGraphicsGetCurrentContext();  

  2. [ gamelayer renderInContext:myCGContext ];  

六、變換

要爲圖層加上一個三維變換或者仿射變換,可以分別設置圖層的 transform 或 affineTransform 屬性。

[java] view plaincopyprint?

  1. roleview.layer.transform = CATransform3DMakeScale( -1.0,-1.0,1.0);  

  2. CGAffineTransform transform = CGAffineTransformMakeRotation(45.0);  

  3. backgroundView.layer.affineTransform =transform ;  

七、圖層動畫


Quartz Core 的能力遠遠不止一個簡單的畫板式圖層。他可以將一個二維物體變換爲一個令人瞠目結舌的三維紋理,用於創建NB的轉場動畫。

我之前寫過一篇介紹轉場動畫的文章,那是一種在不同 UIView 對象之間進行過度的手段。你可以直接將轉場動畫用於圖層或子圖層。動畫可以作爲 CAtransition 對象創建出來。

圖層轉場增強了現有的 CATransition 類,爲其提供了一種方法,能用Quartz Core 的動畫引擎來添加動畫。這令開發者可以利用Quartz Core提供的三維功能,而不必對代碼做大的改動。當圖層被動畫使,一個 CATransition 或CAAnimation 對象會被附加在圖層上。然後圖層會調用Quartz Core,分支出一個新線程,負責動畫的全部圖形處理工作。開發者秩序加入期望的動畫,就可以提升一個現有圖層的功能。用下面的例子代碼,可以創建一個轉場:

[java] view plaincopyprint?

  1. CATransition* animation = [[CATransition alloc]init];  

  2.     animation.duration =1.0;  

  3.     animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];  

  4.     animation.type = kCATransitionPush;  

  5.     animation.subtype = kCATransitionFromRight;  

警告:到目前爲止,噁心的的蘋果允許用戶創建的轉場類型仍然極其有限。Quartz Core 框架內部還支持相當多的其他轉場效果,例如自然翻頁和縮放轉場等,但是受到限制,只能有蘋果自己的應用程序使用。(噁心吧)

通過創建一個CABasicAnimation 對象,你就可以創建出一個動畫。下面的例子創建了一個動畫,將圖層旋轉了整整360度:

[java] view plaincopyprint?

  1. CABasicAnimation *animation = [CABasicAnimation  animationWithKeyPath:@"transform"];  

  2.     animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.1415001.0)];  

  3.     animation.duration =3.0;  

  4.     animation.cumulative =YES;  

  5.     animation.repeatCount=2;  

創建好之後,你可以直接將動畫或者轉場應用到一個圖層上:

[java] view plaincopyprint?

  1. [mapView.layer addAnimation:animation forKey:@"animation"];  

八、圖層變換

Quartz Core 的渲染能力可以像三維一樣對二維圖像進行任意操縱。一個圖像可以在x-y-z 三維軸上進行任意角度旋轉、縮放和扭曲。CATransform3D 函數族是蘋果的Cover Flow 技術 以及 iPhone 上使用的其他美觀特效的幕後力量。iPhone 支持包括縮放、旋轉、仿射、平移等。

變換實在單獨的圖層上執行的,因此多個變換可以在一個圖層表面上同時進行。Quartz Core 框架用 CATransform3D 對象來執行變換。這個對象作用於視圖的圖層,根據期望的三維設置對圖層進行彎折或者其他操作。應用程序可以仍然將對象看作是二維的,但是當對象呈現給用戶時,會遵從已經作用於圖層之上的任何變換。下面的例子創建了一個變換,目的是對一個圖層進行旋轉:

[java] view plaincopyprint?

  1. CATransform3D myTransform;  

  2. myTransform = CATransform3DMakeRotation(angle,x,y,z);  

CATransform3DMakeRotation 函數創建了一個變換,對一個圖形進行旋轉,旋轉角度angle 單位爲弧度,軸爲 x-y-z 。x-y-z 的值定義了軸上在各個方向上的度量(介於-1和+1之間)。在一個軸上賦予值,就會指示變換繞該軸進行旋轉。可以把這些值看作是插在圖像上的草棍。如果草棍是沿着 x 軸插進去的,那麼圖像將繞着草棍垂直旋轉。你可以使用不同角度值作爲軸,產生出更復雜的轉動。不過對於大多數用途來說,用-1 和 +1 這兩個值就夠了。


要將一個圖層繞水平軸轉動(垂直轉動)45度,可以使用下面的代碼:

[java] view plaincopyprint?

  1. myTransform = CATransform3DMakeRotation(0.78,1.0,0.0,0.0);//0.78 是角度45度換成弧度得到的  

要在水平方向上轉動同樣的角度,可以換成 y 軸指定一個值:

[java] view plaincopyprint?

  1. myTransform = CATransform3DMakeRotation(0.78,0.0,1.0,0.0);  

你可以自己編寫一個角度轉弧度的函數:

[java] view plaincopyprint?

  1. double radians(float degrees){  

  2.    return (degrees*3.14159265)/180.0;  

  3. }  

當你創建的時候就調用這個函數:

[java] view plaincopyprint?

  1. myTransform = CATransform3DMakeRotation( radians(45.0),0.0,1.0,0.0);  

 變換創建完畢之後,就要作用於你要操縱的圖層了。CALayer 對象提供了一個 transform屬性,可以用來將變換附加到圖層之上。圖層將會執行任何賦予這個屬性的變換:

[java] view plaincopyprint?

  1. roleView.layer.transform = myTransform;  

 當這個對象被顯示出來時,會按照應用在他上面的變換進行顯示。在你的代碼裏,還是會將這個對象作爲一個二維物體來引用,但是他會根據變換來進行渲染。

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