CoreAnimation程式設計指南之幾何變換
本章介紹圖層的幾何組成部分,及他們之間的相互關,同時介紹如何變換矩陣可以產生複雜的視覺效果。
1.1 圖層的座標系
圖層的座標系在不同平臺上面具有差異性。在iOS系統中,預設的座標系統原點在圖層的中心左上角地方,原點向右和向下為正值。在Mac OS X系統中,預設的座標系原點在圖層的中心左下角地方,原點向右和向上為正值。座標系的所有值都是浮點型別。你在任何平臺上面建立的圖層都採用該平臺預設的座標系。
每個圖層定義並維護自己的座標系,它裡面的全部內容都由此相關的座標系指定位置。該準則同時適應於圖層自己的內容和它的任何子圖層。因為任何圖層定義了它自己的座標系,CALayer類提供相應的方法用於從一個圖層座標系的點、矩形、大小值轉化為另一個圖層座標系相應的值。
一些基於圖層的屬性使用單元座標空間測量它們的值。單元座標空間指定圖層邊界的相對值,而不是絕對值。單元座標空間給定的x和y的值總是在0.0到1.0之間。指定一個沿X軸的值為0.0的點,得到的是圖層左邊緣的一個點,而指定一個1.0的點,則是圖層右邊緣的一個點。(對 Y軸而言,如果是在iOS系統,則0.0對應於頂部的點,而1.0則是底部的點,而在Mac OS X系統,得到的剛好相反,就如之前提到的座標系不同一樣)。而點(0.5,0.5)則剛好是圖層的中心點。
1.2 指定圖層的幾何
雖然圖層和圖層樹與檢視和檢視的結構在很多方面具有相似性,但是圖層的幾何卻不同,它更加簡單通俗。圖層的所有幾何屬性,包括圖層的矩陣變換,都可以隱式和顯式動畫。
下圖顯示可以在上下文中指定圖層幾何的屬性:
圖 1 CALayer的幾何屬性
圖層的position屬性是一個CGPoint的值,它指定圖層相當於它父圖層的位置,該值基於父圖層的座標系。
圖層的bounds屬性是一個CGRect的值,指定圖層的大小(bounds.size)和圖層的原點(bounds.origin)。當你重寫圖層的重畫方法的時候,bounds的原點可以作為圖形上下文的原點。
圖層擁有一個隱式的frame,它是position,bounds,anchorPoint和transform屬性的一部分。設定新的frame將會相應的改變圖層的position和bounds屬性,但是frame本身並沒有被儲存。但是設定新的frame時候,bounds的原點不受干擾,bounds的大小變為frame的大小,即bounds.size=frame.size。圖層的位置被設定為相對於錨點(anchor point)的適合位置。當你設定frame的值的時候,它的計算方式和position、bounds、和anchorPoint的屬性相關。
圖層的anchorPoint屬性是一個CGPoint值,它指定了一個基於圖層bounds的符合位置座標系的位置。錨點(anchor point)指定了bounds相對於position的值,同時也作為變換時候的支點。錨點使用單元空間座標系表示,(0.0,0.0)點接近圖層的原點,而(1.0,1.0)是原點的對角點。改變圖層的父圖層的變換屬性(如果存在的話)將會影響到anchorPoint的方向,具體變化取決於父圖層座標系的Y軸。
當你設定圖層的frame屬性的時候,position會根據錨點(anchorPoint)相應的改變,而當你設定圖層的position屬性的時候,bounds會根據錨點(anchorPoint)做相應的改變。
iOS 注意:以下示例描述基於Mac OS X的圖層,它的座標系原點基於左下角。在iOS上面,圖層的座標系原點位於左上角,原點向下和向右為正值。這變化用具體數值顯示,而不是概念描述。
下圖描述了基於錨點的三個示例值:
圖 2 三個錨點值
anchorPoint預設值是(0.5,0.5),位於圖層邊界的中心點(如上圖顯示),B點把anchorPoint設定為(0.0,0.5)。最後C點(1.0,0.0)把圖層的position設定為圖層frame的右下角。該圖適用於Mac OS X的圖層。在iOS系統裡面,圖層使用不同的座標系,相應的(0.0,0.0)位於左上角,而(1.0,1.0)位於右下角。
圖層的frame、bounds、position和anchorPoint關係如下圖所示:
圖 3 圖層原點 :基於(0.5,0.5)
在該示例中,anchorPoint預設值為(0.5,0.5),位於圖層的中心點。圖層的position值為(100.0,100.0),bounds為(0.0,0.0,120,80.0)。通過計算得到圖層的frame為(40.0,60.0,120.0,80.0)。
如果你新建立一個圖層,則只有設定圖層的frame為(40.0,60.0,120.0,80.0),相應的position屬性值將會自動設定為(100.0,100.0),而bounds會自動設定為(0.0,0.0,120.0,80.0)。
下圖顯示一個圖層具有相同的frame(如上圖),但是在該圖中它的anchorPoint屬性值被設定為(0.0,0.0),位於圖層的左下角位置。
圖層的frame值同樣為(40.0,60.0,120.0,80.0),bounds的值不變,但是圖層的position值已經改變為(40.0,60.0)。
圖層的幾何外形和Cocoa檢視另外一個不同地方是,你可以設定圖層的一個邊角的半徑來把圖層顯示為圓角。圖層的cornerRadius屬性指定了重繪圖層內容,剪下子圖層,繪製圖層的邊界和陰影的時候時候圓角的半徑。
圖層的zPosition屬性值指定了該圖層位於Z軸上面位置,zPosition用於設定圖層相對於圖層的同級圖層的可視位置。
1.3 圖層的幾何變換
圖層一旦建立,你就可以通過矩陣變換來改變一個圖層的幾何形狀。CATransform3D的資料結構定義一個同質的三維變換(4x4 CGFloat值的矩陣),用於圖層的旋轉,縮放,偏移,歪斜和應用的透視。
圖層的兩個屬性指定了變換矩陣:transform和sublayerTransform屬性。圖層的transform屬性指定的矩陣結合圖層的anchorPoint屬性作用於圖層和圖層的子圖層上面。圖 3顯示在使用anchorPoint預設值(0.5,0.5)的時候旋轉和縮放變換如何影響一個圖層。而圖 4顯示了同樣的矩陣變換在anchorPoint為(0.0,0.0)的時候如何改變一個圖層。圖層的sublayerTransform屬性指定的矩陣只會影響圖層的子圖層,而不會對圖層本身產生影響。
你可以通過以下的任何一個方法改變CATransform3D的資料結構:
- 使用CATransform3D函式
- 直接修改資料結構的成員
- 使用鍵-值編碼改變鍵路徑
CATransform3DIdentity是單位矩陣,該矩陣沒有縮放、旋轉、歪斜、透視。把該矩陣應用到圖層上面,會把圖層幾何屬性修改為預設值。
1.3.1 變換函式
使用變換函式可以在核心動畫裡面在操作矩陣。你可以使用這些函式(如下表)去建立一個矩陣一般後面用於改變圖層或者它的子圖層的transform和sublayerTransform屬性。變換函式或者直接操或者返回一個CATransform3D的資料結構。這可以讓你能夠構建簡單或複雜的轉換,以便重複使用。
表 1 CATransform3D 變換函式 :偏移、旋轉和縮放
Function |
Use |
|
Returns a transform that translates by '(tx, ty, tz)'. t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1]. |
|
Translate 't' by '(tx, ty, tz)' and return the result: * t' = translate(tx, ty, tz) * t. |
|
Returns a transform that scales by `(sx, sy, sz)': * t' = [sx 0 0 0; 0 sy 0 0; 0 0 sz 0; 0 0 0 1]. |
|
Scale 't' by '(sx, sy, sz)' and return the result: * t' = scale(sx, sy, sz) * t. |
|
Returns a transform that rotates by 'angle' radians about the vector '(x, y, z)'. If the vector has length zero the identity transform is returned. |
|
Rotate 't' by 'angle' radians about the vector '(x, y, z)' and return the result. t' = rotation(angle, x, y, z) * t. |
旋轉的單位採用弧度(radians),而不是角度(degress)。以下兩個函式,你可以在弧度和角度之間切換。
1 2 |
|
核心動畫 提供了用於轉換矩陣的變換函式CATransform3DInvert。一般是用反轉點內轉化物件提供反向轉換。當你需要恢復一個已經被變換了的矩陣的時候,反轉將會非常有幫助。反轉矩陣乘以逆矩陣值,結果是原始值。
變換函式同時允許你把CATransform3D矩陣轉化為CGAffineTransform(仿射)矩陣,前提是CATransform3D矩陣採用如下表示方法。
表 2 CATransform3D 與 CGAffineTransform 轉換
Function |
Use |
|
Returns a |
|
Returns |
|
Returns the affine transform represented by the passed |
變換函式同時提供了可以比較一個變換矩陣是否是單位矩陣,或者兩個矩陣是否相等。
表 3 CATransform3D 相等測試
Function |
Use |
|
Returns |
|
Returns |
1.3.2 修改變換的資料結構
你可以修改CATransform3D的資料結構的元素為任何其他你想要的資料值。程式碼1包含了CATransform3D資料結構的定義,結構的成員都在其相應的矩陣位置。
程式碼 1 CATransform3D structure
1 2 3 4 5 6 7 8 9 |
|
程式碼2中的示例說明了如何配置一個CATransform3D一個角度變換。
程式碼 2 直接修改CATransform3D資料結構
1 2 3 4 |
|
1.3.3 通過鍵值路徑修改變換
核心動畫擴充套件了鍵-值編碼協議,允許通過關鍵路徑獲取和設定一個圖層的CATransform3D矩陣的值。表4描述了圖層的transform和sublayerTransform屬性的相應關鍵路徑。
表 4 CATransform3D key paths
Field Key Path |
Description |
rotation.x |
The rotation, in radians, in the x axis. |
rotation.y |
The rotation, in radians, in the y axis. |
rotation.z |
The rotation, in radians, in the z axis. |
rotation |
The rotation, in radians, in the z axis. This is identical to setting the rotation.z field. |
scale.x |
Scale factor for the x axis. |
scale.y |
Scale factor for the y axis. |
scale.z |
Scale factor for the z axis. |
scale |
Average of all three scale factors. |
translation.x |
Translate in the x axis. |
translation.y |
Translate in the y axis. |
translation.z |
Translate in the z axis. |
translation |
Translate in the x and y axis. Value is an NSSize or CGSize. |
你不可以通過Objective-C 2.0的屬性來設定結構域的值,比如下面的程式碼將會無法正常執行:
1 |
|
替換的辦法是,你必須通過setValue:forKeyPath:或者valueForKeyPath:方法,具體如下:
1 |
|