
時(shí)隔三天后,各位終于等到我的簡書更新了.今天我的主題是如何在圖層上實(shí)現(xiàn)三維變形.
在UIView上,我們可以使用CGAffineTransform來對(duì)視圖進(jìn)行:平移(translation),旋轉(zhuǎn)(Rotation),縮放(scale),傾斜(Invert)操作,但這些操作是沒有動(dòng)態(tài)立體效果的, 這只能稱為二維變形.而在圖層中,我們可以使用CATransform3D進(jìn)行"視角旋轉(zhuǎn)"來完成三維變形的效果,但這常稱為2.5D,而非真正意義上的3D,因?yàn)樗荒茏寛D層真正成為三維對(duì)象,而只是模擬出三維的動(dòng)畫效果.
請(qǐng)看三維動(dòng)畫效果:

下面我就來一步一步的來實(shí)現(xiàn)它.
1.從圖中的顯示效果來看,我們需要?jiǎng)?chuàng)建六個(gè)圖層,來表示一個(gè)立體圖形六個(gè)不同的面.并且創(chuàng)建一個(gè)CATransformLayer類來作為容器:
/**底部容器*/
@property (nonatomic,strong) CATransformLayer *contentLayer;
/**上面*/
@property (nonatomic,strong) CALayer *topLayer;
/**下面*/
@property (nonatomic,strong) CALayer *bottomLayer;
/**左面*/
@property (nonatomic,strong) CALayer *leftLayer;
/**右面*/
@property (nonatomic,strong) CALayer *rightLayer;
/**前面*/
@property (nonatomic,strong) CALayer *frontLayer;
/**后面*/
@property (nonatomic,strong) CALayer *backLayer;
通常情況下,像這種批量創(chuàng)建對(duì)象的工作,不要做傻傻的碼農(nóng),要學(xué)會(huì)封裝,這樣我們只需要傳入圖層所必須的變量參數(shù)就可以創(chuàng)建一個(gè)圖層了.
- (CALayer *)layerAtX:(CGFloat)x y:(CGFloat)y z:(CGFloat)z color:(UIColor *)color transform:(CATransform3D)transform{
CALayer *layer = [CALayer layer];
layer.backgroundColor = color.CGColor;
layer.bounds = CGRectMake(0, 0, 100, 100);
layer.position = CGPointMake(x, y);
layer.zPosition = z;
layer.transform = transform;
[self.contentLayer addSublayer:layer];
return layer;
}
其中,我要說一下上面代碼中l(wèi)ayer的zPosition與transfrom屬性,在這個(gè)例子中,我會(huì)使用CATransformLayer類,這個(gè)類是CALayer的子類,在官方文檔上有一句話是這么描述的"CATransformlayer objects are used to create sure 3D layer hierarchies".那他到底和CALayer有什么區(qū)別呢?是這樣的.在CALayer中的zPosition屬性,如果只使用CALayer,那么zPosition只能用于計(jì)算圖層的顯示順序,這樣會(huì)使圖形看起來是扁平的.而在CATransformLayer這個(gè)類當(dāng)中,zPosition就可以用來決定空間位置.他會(huì)讓圖形的position不限于X,Y軸上,也可以在Z軸上設(shè)置相應(yīng)值來讓圖形添加景深,從而讓圖形具有立體效果.所以,x,y,z分別是X軸,Y軸,Z軸方向的值.
下面說說本文的核心部分:CALayer的transfrom屬性:這個(gè)屬性主要是操作CATranfrom3D類對(duì)圖層進(jìn)行三維變形.在我們這個(gè)例子中,主要是對(duì)圖層進(jìn)行旋轉(zhuǎn),所以著重講一下CATranfrom3D類當(dāng)中進(jìn)行3D旋轉(zhuǎn)的方法:
CA_EXTERN CATransform3D CATransform3DMakeRotation (CGFloat angle, CGFloat x,
CGFloat y, CGFloat z)
可以看出來,這是一個(gè)c語言封裝好的函數(shù),里面的參數(shù)我來說明:第一個(gè)參數(shù):里面的角度是圖層需要旋轉(zhuǎn)的角度,是以弧度為單位,我列舉一下幾個(gè)常用的:M_PI是表示180度,M_PI_2表示90度,M_PI_4表示45度.后面的三個(gè)參數(shù)x,y,z:我們知道,在二維形變中,旋轉(zhuǎn)效果是圍繞著一個(gè)點(diǎn)進(jìn)行變化的,而在三維變化中,卻是圍繞著一條軸.而這三個(gè)參數(shù)在立體平面中的坐標(biāo)系中確定一個(gè)點(diǎn),這個(gè)點(diǎn)與圓點(diǎn)(左上角)的連線確定一條軸,我舉一個(gè)特殊的例子:比如繞著y軸旋轉(zhuǎn)45度?繞著y軸旋轉(zhuǎn),那么必然這三個(gè)參數(shù)確定的點(diǎn)在Y軸上,在Y軸上,那么其他值必然為0,所以里面的參數(shù)應(yīng)該這樣填:CATransform3DMakeRotation (M_PI_4, 0, 1, 0);
好了,那么現(xiàn)在初始化CATransformLayer,然后將六個(gè)圖層添加到這個(gè)容器中.
// 創(chuàng)建CATransformLayer對(duì)象
CATransformLayer *contentLayer = [CATransformLayer layer];
contentLayer.frame =self.view.layer.bounds;
CGSize size = contentLayer.bounds.size;
contentLayer.transform = CATransform3DMakeTranslation(size.width / 2, size.height / 2, 0);
self.contentLayer = contentLayer;
[self.view.layer addSublayer:contentLayer];
// 初始化六個(gè)圖層
// 頂部與底部的沿著x軸旋轉(zhuǎn)90度
self.topLayer = [self layerAtX:0 y:-kSize/2 z:0 color:[UIColor redColor] transform:CATransform3DMakeRotation(M_PI_2, 1, 0, 0)];
self.bottomLayer = [self layerAtX:0 y:kSize/2 z:0 color:[UIColor greenColor] transform:CATransform3DMakeRotation(M_PI_2, 1, 0, 0)];
// 左邊與右邊的沿著y軸旋轉(zhuǎn)90度
self.leftLayer = [self layerAtX:-kSize / 2 y:0 z:0 color:[UIColor blueColor] transform:CATransform3DMakeRotation(M_PI_2, 0, 1, 0)];
self.rightLayer = [self layerAtX:kSize/2 y:0 z:0 color:[UIColor blackColor] transform:CATransform3DMakeRotation(M_PI_2, 0, 1, 0)];
// 前面與后面的不需要變化,所以使用CATransform3DIdentity
self.frontLayer = [self layerAtX:0 y:0 z:kSize / 2 color:[UIColor brownColor] transform:CATransform3DIdentity];
self.backLayer = [self layerAtX:0 y:0 z:-kSize / 2 color:[UIColor brownColor] transform:CATransform3DIdentity];
說明一點(diǎn):kSize 是我定義的一個(gè)宏,表示的是這個(gè)正方體的邊長.
現(xiàn)在的視圖上顯示的是什么效果呢

為什么只顯示前面圖層給的brownColor呢?這就是對(duì)的,由于旋轉(zhuǎn)90度后,上下與左右都收在前面圖層的四側(cè),與視圖垂直,所以我們看不到,那么我就給一個(gè)pan手勢,隨著手指的移動(dòng),旋轉(zhuǎn)這個(gè)立體圖形.
- (void)pan:(UIPanGestureRecognizer *)recognizer{
//獲取到的是手指移動(dòng)后,在相對(duì)坐標(biāo)中的偏移量(以手指接觸屏幕的第一個(gè)點(diǎn)為坐標(biāo)原點(diǎn))
CGPoint translation = [recognizer translationInView:self.view];
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DRotate(transform, translation.x * 1 / 100, 0, 1, 0);
transform = CATransform3DRotate(transform, translation.y * - 1 / 100, 1, 0, 0);
self.view.layer.sublayerTransform = transform;
}