W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
CG的前綴告訴我們,CGAffineTransform
類型屬于Core Graphics框架,Core Graphics實(shí)際上是一個(gè)嚴(yán)格意義上的2D繪圖API,并且CGAffineTransform
僅僅對(duì)2D變換有效。
在第三章中,我們提到了zPosition
屬性,可以用來(lái)讓圖層靠近或者遠(yuǎn)離相機(jī)(用戶視角),transform
屬性(CATransform3D
類型)可以真正做到這點(diǎn),即讓圖層在3D空間內(nèi)移動(dòng)或者旋轉(zhuǎn)。
和CGAffineTransform
類似,CATransform3D
也是一個(gè)矩陣,但是和2x3的矩陣不同,CATransform3D
是一個(gè)可以在3維空間內(nèi)做變換的4x4的矩陣(圖5.6)。
圖5.7 X,Y,Z軸,以及圍繞它們旋轉(zhuǎn)的方向
由圖所見(jiàn),繞Z軸的旋轉(zhuǎn)等同于之前二維空間的仿射旋轉(zhuǎn),但是繞X軸和Y軸的旋轉(zhuǎn)就突破了屏幕的二維空間,并且在用戶視角看來(lái)發(fā)生了傾斜。
舉個(gè)例子:清單5.4的代碼使用了CATransform3DMakeRotation
對(duì)視圖內(nèi)的圖層繞Y軸做了45度角的旋轉(zhuǎn),我們可以把視圖向右傾斜,這樣會(huì)看得更清晰。
結(jié)果見(jiàn)圖5.8,但并不像我們期待的那樣。
清單5.4 繞Y軸旋轉(zhuǎn)圖層
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//rotate the layer 45 degrees along the Y axis
CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
self.layerView.layer.transform = transform;
}
@end
圖5.9?CATransform3D
的m34
元素,用來(lái)做透視
m34
的默認(rèn)值是0,我們可以通過(guò)設(shè)置m34
為-1.0 /?d
來(lái)應(yīng)用透視效果,d
代表了想象中視角相機(jī)和屏幕之間的距離,以像素為單位,那應(yīng)該如何計(jì)算這個(gè)距離呢?實(shí)際上并不需要,大概估算一個(gè)就好了。
因?yàn)橐暯窍鄼C(jī)實(shí)際上并不存在,所以可以根據(jù)屏幕上的顯示效果自由決定它的防止的位置。通常500-1000就已經(jīng)很好了,但對(duì)于特定的圖層有時(shí)候更小后者更大的值會(huì)看起來(lái)更舒服,減少距離的值會(huì)增強(qiáng)透視效果,所以一個(gè)非常微小的值會(huì)讓它看起來(lái)更加失真,然而一個(gè)非常大的值會(huì)讓它基本失去透視效果,對(duì)視圖應(yīng)用透視的代碼見(jiàn)清單5.5,結(jié)果見(jiàn)圖5.10。
清單5.5 對(duì)變換應(yīng)用透視效果
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//create a new transform
CATransform3D transform = CATransform3DIdentity;
//apply perspective
transform.m34 = - 1.0 / 500.0;
//rotate by 45 degrees along the Y axis
transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
//apply to layer
self.layerView.layer.transform = transform;
}
@end
圖5.11 滅點(diǎn)
Core Animation定義了這個(gè)點(diǎn)位于變換圖層的anchorPoint
(通常位于圖層中心,但也有例外,見(jiàn)第三章)。這就是說(shuō),當(dāng)圖層發(fā)生變換時(shí),這個(gè)點(diǎn)永遠(yuǎn)位于圖層變換之前anchorPoint
的位置。
當(dāng)改變一個(gè)圖層的position
,你也改變了它的滅點(diǎn),做3D變換的時(shí)候要時(shí)刻記住這一點(diǎn),當(dāng)你視圖通過(guò)調(diào)整m34
來(lái)讓它更加有3D效果,應(yīng)該首先把它放置于屏幕中央,然后通過(guò)平移來(lái)把它移動(dòng)到指定位置(而不是直接改變它的position
),這樣所有的3D圖層都共享一個(gè)滅點(diǎn)。
sublayerTransform
屬性如果有多個(gè)視圖或者圖層,每個(gè)都做3D變換,那就需要分別設(shè)置相同的m34值,并且確保在變換之前都在屏幕中央共享同一個(gè)position
,如果用一個(gè)函數(shù)封裝這些操作的確會(huì)更加方便,但仍然有限制(例如,你不能在Interface Builder中擺放視圖),這里有一個(gè)更好的方法。
CALayer
有一個(gè)屬性叫做sublayerTransform
。它也是CATransform3D
類型,但和對(duì)一個(gè)圖層的變換不同,它影響到所有的子圖層。這意味著你可以一次性對(duì)包含這些圖層的容器做變換,于是所有的子圖層都自動(dòng)繼承了這個(gè)變換方法。
相較而言,通過(guò)在一個(gè)地方設(shè)置透視變換會(huì)很方便,同時(shí)它會(huì)帶來(lái)另一個(gè)顯著的優(yōu)勢(shì):滅點(diǎn)被設(shè)置在容器圖層的中點(diǎn),從而不需要再對(duì)子圖層分別設(shè)置了。這意味著你可以隨意使用position
和frame
來(lái)放置子圖層,而不需要把它們放置在屏幕中點(diǎn),然后為了保證統(tǒng)一的滅點(diǎn)用變換來(lái)做平移。
我們來(lái)用一個(gè)demo舉例說(shuō)明。這里用Interface Builder并排放置兩個(gè)視圖(圖5.12),然后通過(guò)設(shè)置它們?nèi)萜饕晥D的透視變換,我們可以保證它們有相同的透視和滅點(diǎn),代碼見(jiàn)清單5.6,結(jié)果見(jiàn)圖5.13。
圖5.13 通過(guò)相同的透視效果分別對(duì)視圖做變換
我們既然可以在3D場(chǎng)景下旋轉(zhuǎn)圖層,那么也可以從背面去觀察它。如果我們?cè)谇鍐?.4中把角度修改為M_PI
(180度)而不是當(dāng)前的M_PI_4
(45度),那么將會(huì)把圖層完全旋轉(zhuǎn)一個(gè)半圈,于是完全背對(duì)了相機(jī)視角。
那么從背部看圖層是什么樣的呢,見(jiàn)圖5.14
圖5.15 反方向變換的嵌套圖層
注意做了-45度旋轉(zhuǎn)的內(nèi)部圖層是怎樣抵消旋轉(zhuǎn)45度的圖層,從而恢復(fù)正常狀態(tài)的。
如果內(nèi)部圖層相對(duì)外部圖層做了相反的變換(這里是繞Z軸的旋轉(zhuǎn)),那么按照邏輯這兩個(gè)變換將被相互抵消。
驗(yàn)證一下,相應(yīng)代碼見(jiàn)清單5.7,結(jié)果見(jiàn)5.16
清單5.7 繞Z軸做相反的旋轉(zhuǎn)變換
@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIView *outerView;
@property (nonatomic, weak) IBOutlet UIView *innerView;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//rotate the outer layer 45 degrees
CATransform3D outer = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
self.outerView.layer.transform = outer;
//rotate the inner layer -45 degrees
CATransform3D inner = CATransform3DMakeRotation(-M_PI_4, 0, 0, 1);
self.innerView.layer.transform = inner;
}
@end
圖5.17 繞Y軸做相反旋轉(zhuǎn)的預(yù)期結(jié)果。
但其實(shí)這并不是我們所看到的,相反,我們看到的結(jié)果如圖5.18所示。發(fā)什么了什么呢??jī)?nèi)部的圖層仍然向左側(cè)旋轉(zhuǎn),并且發(fā)生了扭曲,但按道理說(shuō)它應(yīng)該保持正面朝上,并且顯示正常的方塊。
這是由于盡管Core Animation圖層存在于3D空間之內(nèi),但它們并不都存在同一個(gè)3D空間。每個(gè)圖層的3D場(chǎng)景其實(shí)是扁平化的,當(dāng)你從正面觀察一個(gè)圖層,看到的實(shí)際上由子圖層創(chuàng)建的想象出來(lái)的3D場(chǎng)景,但當(dāng)你傾斜這個(gè)圖層,你會(huì)發(fā)現(xiàn)實(shí)際上這個(gè)3D場(chǎng)景僅僅是被繪制在圖層的表面。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: