1. CGAffineTransform
-
CGAffineTransform基礎(chǔ)
UIView有一個(gè)CGAffineTransform類型的屬性走孽,叫transform抹恳,用于在二維空間做旋轉(zhuǎn)哺眯,縮放和平移。CALayer也有一個(gè)與之對(duì)應(yīng)的屬性叫affineTransform。CGAffineTransform所涉及的矩陣知識(shí)蕴潦,這里有一篇文章說(shuō)得很清楚: IOS矩陣之后的數(shù)學(xué)知識(shí)。CGPoint與CGAffineTransform的關(guān)系如圖:
用CGPoint的每一列和CGAffineTransform矩陣的每一行對(duì)應(yīng)元素相乘再求和,就形成了一個(gè)新的CGPoint類型的結(jié)果惋戏。要解釋一下圖中顯示的灰色元素,為了能讓矩陣做乘法他膳,左邊矩陣的列數(shù)一定要和右邊矩陣的行數(shù)個(gè)數(shù)相同响逢,所以要給矩陣填充一些標(biāo)志值,使得既可以讓矩陣做乘法棕孙,又不改變運(yùn)算結(jié)果舔亭,并且沒(méi)必要存儲(chǔ)這些添加的值,因?yàn)樗鼈兊闹挡粫?huì)發(fā)生變化蟀俊,但是要用來(lái)做運(yùn)算钦铺。具體運(yùn)算過(guò)程是這樣的:
當(dāng)對(duì)圖層應(yīng)用變換矩陣,圖層矩形內(nèi)的每一個(gè)點(diǎn)都被相應(yīng)地做變換肢预,從而形成一個(gè)新的四邊形的形狀矛洞。CGAffineTransform中的“仿射”的意思是無(wú)論變換矩陣用什么值,圖層中平行的兩條線在變換之后任然保持平行烫映,CGAffineTransform可以做出任意符合上述標(biāo)注的變換沼本。下圖顯示了一些仿射的和非仿射的變換:
-
CGAffineTransform應(yīng)用
CGAffineTransform的前綴CG即Core Graphics,Core Graphics提供了一系列函數(shù)锭沟,對(duì)完全沒(méi)有數(shù)學(xué)基礎(chǔ)的開發(fā)者也能夠簡(jiǎn)單地做一些變換擅威。如下幾個(gè)函數(shù)都創(chuàng)建了一個(gè)CGAffineTransform實(shí)例:
/* Return a transform which translates by `(tx, ty)':
t' = [ 1 0 0 1 tx ty ] */
CG_EXTERN CGAffineTransform CGAffineTransformMakeTranslation(CGFloat tx,
CGFloat ty) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Return a transform which scales by `(sx, sy)':
t' = [ sx 0 0 sy 0 0 ] */
CG_EXTERN CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Return a transform which rotates by `angle' radians:
t' = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] */
CG_EXTERN CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
舉個(gè)栗子,點(diǎn)擊屏幕冈钦,將子視圖順時(shí)針旋轉(zhuǎn)45度:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController{
UIView *layerView;
}
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
layerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];
layerView.backgroundColor = [UIColor purpleColor];
layerView.center = self.view.center;
[self.view addSubview:layerView];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[UIView animateWithDuration:1.25f animations:^{
CGAffineTransform transform = CGAffineTransformMakeRotation(45.0f/180.0f*M_PI);
layerView.layer.affineTransform = transform;
}];
}
@end
運(yùn)行效果:
π是弧度單位郊丛,其對(duì)應(yīng)的角度為180度李请,Core Animation使用弧度最為參數(shù)
弧度轉(zhuǎn)角度:
#define RADIANS_TO_DEGREES(x) ((x)/M_PI*180.0)
角度轉(zhuǎn)弧度:
#define DEGREES_TO_RADIANS(x) ((x)/180.0*M_PI)
-
復(fù)合變換
CGAffineTransformConcat方法可以混合兩個(gè)已經(jīng)存在的變換矩陣,在兩個(gè)變換的基礎(chǔ)上創(chuàng)建一個(gè)新的變換厉熟,舉個(gè)栗子导盅,修改上面的代碼:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController{
UIView *layerView;
}
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
layerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];
layerView.backgroundColor = [UIColor purpleColor];
layerView.center = self.view.center;
[self.view addSubview:layerView];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[UIView animateWithDuration:1.25f animations:^{
//CGAffineTransform transform = CGAffineTransformMakeRotation(45.0f/180.0f*M_PI);
//layerView.layer.affineTransform = transform;
CGAffineTransform rotation = CGAffineTransformMakeRotation(45.0f/180.0f*M_PI);
CGAffineTransform scale = CGAffineTransformMakeScale(1.5f, 1.5f);
CGAffineTransform transform = CGAffineTransformConcat(rotation, scale);
layerView.layer.affineTransform = transform;
}];
}
@end
運(yùn)行效果:
CGAffineTransformConcat方法只能接受兩個(gè)參數(shù),要做兩種以上的復(fù)合變換的話揍瑟,需要用到下面這些方法:
/* Translate `t' by `(tx, ty)' and return the result:
t' = [ 1 0 0 1 tx ty ] * t */
CG_EXTERN CGAffineTransform CGAffineTransformTranslate(CGAffineTransform t,
CGFloat tx, CGFloat ty) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Scale `t' by `(sx, sy)' and return the result:
t' = [ sx 0 0 sy 0 0 ] * t */
CG_EXTERN CGAffineTransform CGAffineTransformScale(CGAffineTransform t,
CGFloat sx, CGFloat sy) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Rotate `t' by `angle' radians and return the result:
t' = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] * t */
CG_EXTERN CGAffineTransform CGAffineTransformRotate(CGAffineTransform t,
CGFloat angle) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
舉個(gè)栗子白翻,我們來(lái)用這些函數(shù)組合一個(gè)更加復(fù)雜的變換,先縮小50%绢片,再順時(shí)針旋轉(zhuǎn)30度滤馍,最后向右移動(dòng)200個(gè)像,繼續(xù)修改上面的代碼:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController{
UIView *layerView;
}
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
layerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];
layerView.backgroundColor = [UIColor purpleColor];
layerView.center = self.view.center;
[self.view addSubview:layerView];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[UIView animateWithDuration:1.25f animations:^{
//CGAffineTransform transform = CGAffineTransformMakeRotation(45.0f/180.0f*M_PI);
//layerView.layer.affineTransform = transform;
//CGAffineTransform rotation = CGAffineTransformMakeRotation(45.0f/180.0f*M_PI);
//CGAffineTransform scale = CGAffineTransformMakeScale(1.5f, 1.5f);
//CGAffineTransform transform = CGAffineTransformConcat(rotation, scale);
//layerView.layer.affineTransform = transform;
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformScale(transform, 0.5f, 0.5f);
transform = CGAffineTransformRotate(transform, 30.0f/180.0f*M_PI);
transform = CGAffineTransformTranslate(transform, 200.0f, 0.0f);
layerView.layer.affineTransform = transform;
}];
}
@end
運(yùn)行效果:
有些需要注意的地方:圖片向右邊發(fā)生了平移底循,但并沒(méi)有指定距離那么遠(yuǎn)(200像素)巢株,另外它還有點(diǎn)向下發(fā)生了平移。原因在于當(dāng)你按順序做了變換熙涤,上一個(gè)變換的結(jié)果將會(huì)影響之后的變換阁苞,所以200像素的向右平移同樣也被旋轉(zhuǎn)了30度,縮小了50%祠挫,所以它實(shí)際上是斜向移動(dòng)了100像素那槽。這意味著變換的順序會(huì)影響最終的結(jié)果,也就是說(shuō)旋轉(zhuǎn)之后的平移和平移之后的旋轉(zhuǎn)結(jié)果可能不同等舔。
2. CATransform3D
-
CATransform3D基礎(chǔ)
affineTransform屬性只能用來(lái)做2D變換骚灸,CALayer還有一個(gè)用來(lái)做3D變換的屬性叫transform,其類型是CATransform3D類型慌植。和CGAffineTransform類似甚牲,CATransform3D也是一個(gè)矩陣,但是和2x3的矩陣不同涤浇,CATransform3D是一個(gè)可以在3維空間內(nèi)做變換的4x4的矩陣:
我們對(duì)X軸和Y軸比較熟悉了,分別以右和下為正方向魔慷,Z軸和這兩個(gè)軸分別垂直只锭,指向視角外為正方向:
由圖所見,繞Z軸的旋轉(zhuǎn)等同于之前二維空間的仿射旋轉(zhuǎn)院尔,但是繞X軸和Y軸的旋轉(zhuǎn)就突破了屏幕的二維空間蜻展,并且在用戶視角看來(lái)發(fā)生了傾斜。
-
CATransform3D應(yīng)用
CATransform3D類型的矩陣邀摆,和Core Graphics的函數(shù)類似纵顾,但是3D的平移和旋轉(zhuǎn)多處了一個(gè)z參數(shù),并且旋轉(zhuǎn)函數(shù)除了angle之外多出了x,y,z三個(gè)參數(shù)栋盹,分別決定了每個(gè)坐標(biāo)軸方向上的旋轉(zhuǎn):
/* 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]. */
CA_EXTERN CATransform3D CATransform3DMakeTranslation (CGFloat tx,
CGFloat ty, CGFloat tz)
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
/* 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]. */
CA_EXTERN CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy,
CGFloat sz)
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
/* 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. */
CA_EXTERN CATransform3D CATransform3DMakeRotation (CGFloat angle, CGFloat x,
CGFloat y, CGFloat z)
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
舉個(gè)栗子施逾,點(diǎn)擊屏幕將子視圖旋轉(zhuǎn)-45度:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController{
UIView *layerView;
}
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
layerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 150.0f, 150.0f)];
layerView.center = self.view.center;
layerView.layer.backgroundColor = [UIColor blueColor].CGColor;
[self.view addSubview:layerView];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[UIView animateWithDuration:1.25f animations:^{
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DRotate(transform, -(45.0f/180.0f*M_PI), 0.0f, 1.0f, 0.0f);
layerView.layer.transform = transform;
}];
}
@end
運(yùn)行效果:
看起來(lái)好像只是寬度被壓扁了而已,這是因?yàn)槲覀冊(cè)谟靡粋€(gè)斜向的視角看它,而不是透視汉额。
-
透視效果
CATransform3D的透視效果通過(guò)一個(gè)矩陣中一個(gè)很簡(jiǎn)單的元素來(lái)控制:m34曹仗。m34用于按比例縮放X和Y的值來(lái)計(jì)算到底要離視角多遠(yuǎn),其默認(rèn)值是0蠕搜,我們可以通過(guò)設(shè)置m34為-1.0 / d來(lái)應(yīng)用透視效果怎茫,d代表了想象中視角相機(jī)和屏幕之間的距離,以像素為單位妓灌,那應(yīng)該如何計(jì)算這個(gè)距離呢轨蛤?實(shí)際上并不需要如何計(jì)算,大概估算一個(gè)就好了虫埂,一般是500-1000祥山。修改上面的代碼:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController{
UIView *layerView;
}
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
layerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 150.0f, 150.0f)];
layerView.center = self.view.center;
layerView.layer.backgroundColor = [UIColor blueColor].CGColor;
[self.view addSubview:layerView];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[UIView animateWithDuration:1.25f animations:^{
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -1.0f / 500.0f;
transform = CATransform3DRotate(transform, -(45.0f/180.0f*M_PI), 0.0f, 1.0f, 0.0f);
layerView.layer.transform = transform;
}];
}
@end
運(yùn)行效果:
-
滅點(diǎn)
當(dāng)在透視角度繪圖的時(shí)候,遠(yuǎn)離相機(jī)視角的物體將會(huì)變小變遠(yuǎn)告丢,當(dāng)遠(yuǎn)離到一個(gè)極限距離枪蘑,它們可能就縮成了一個(gè)點(diǎn),于是所有的物體最后都匯聚消失在同一個(gè)點(diǎn)岖免,這個(gè)點(diǎn)叫滅點(diǎn)岳颇。
Core Animation定義了滅點(diǎn)位于變換圖層的anchorPoint,這就是說(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埂淮,這樣操作起來(lái)很麻煩,CALayer有一個(gè)叫做sublayerTransform的屬性可以解決這個(gè)問(wèn)題写隶。
sublayerTransform也是CATransform3D類型倔撞,但和對(duì)一個(gè)圖層的變換不同,它影響到所有的子圖層慕趴,這意味著你可以一次性對(duì)包含這些圖層的容器做變換痪蝇。
使用sublayerTransform鄙陡,滅點(diǎn)被設(shè)置在容器圖層的中點(diǎn),從而不需要再對(duì)子圖層分別設(shè)置了霹俺。這意味著你可以隨意使用position和frame來(lái)放置子圖層柔吼,而不需要把它們放置在屏幕中點(diǎn),然后為了保證統(tǒng)一的滅點(diǎn)用變換來(lái)做平移丙唧。
-
doubleSided
CALayer有一個(gè)叫做doubleSided的屬性來(lái)控制圖層的背面是否要被繪制愈魏,這是一個(gè)BOOL類型,默認(rèn)為YES想际,如果設(shè)置為NO培漏,那么當(dāng)圖層正面從相機(jī)視角消失的時(shí)候,它將不會(huì)被繪制胡本。舉個(gè)栗子:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController{
UIView *topView;
UIView *bottomView;
}
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIImage *image = [UIImage imageNamed:@"3"];
topView = [[UIView alloc] initWithFrame:CGRectMake(85.0f, 100.0f, 150.0f, 150.0f)];
bottomView = [[UIView alloc] initWithFrame:CGRectMake(85.0f, 300.0f, 150.0f, 150.0f)];
bottomView.layer.doubleSided = NO;
[self configView:topView image:image];
[self configView:bottomView image:image];
}
-(void)configView:(UIView *)aView image:(UIImage *)aImage{
aView.layer.backgroundColor = [UIColor greenColor].CGColor;
aView.layer.contents = (__bridge id _Nullable)(aImage.CGImage);
aView.layer.contentsGravity = kCAGravityResizeAspect;
aView.layer.contentsScale = [UIScreen mainScreen].scale;
[self.view addSubview:aView];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[UIView animateWithDuration:5.0f animations:^{
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DRotate(transform, M_PI, 0.0f, 1.0f, 0.0f);
topView.layer.transform = transform;
bottomView.layer.transform = transform;
}];
}
@end
運(yùn)行效果:
3. 固體對(duì)象
現(xiàn)在我們懂得了在3D空間的一些圖層布局的基礎(chǔ)牌柄,接下來(lái)試著創(chuàng)建一個(gè)固態(tài)的3D對(duì)象(實(shí)際上是一個(gè)技術(shù)上所謂的空洞對(duì)象,但它以固態(tài)呈現(xiàn))侧甫,我們用三個(gè)獨(dú)立的視圖來(lái)構(gòu)建一個(gè)殘缺的正方體
Interface Build布局如圖:
代碼:
#import "TestViewController.h"
@interface TestViewController ()
@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nonatomic, strong) IBOutletCollection(UIView) NSArray *faces;
@end
@implementation TestViewController
- (void)addFace:(NSInteger)index withTransform:(CATransform3D)transform{
//get the face view and add it to the container
UIView *face = self.faces[index];
[self.containerView addSubview:face];
//center the face view within the container
CGSize containerSize = self.containerView.bounds.size;
face.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0);
// apply the transform
face.layer.transform = transform;
}
- (void)viewDidLoad{
[super viewDidLoad];
//set up the container sublayer transform
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0 / 500.0;
self.containerView.layer.sublayerTransform = perspective;
//add cube face 1
CATransform3D transform = CATransform3DMakeTranslation(0, 0, 100);
[self addFace:0 withTransform:transform];
//add cube face 2
transform = CATransform3DMakeTranslation(100, 0, 0);
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
[self addFace:1 withTransform:transform];
//add cube face 3
transform = CATransform3DMakeTranslation(0, -100, 0);
transform = CATransform3DRotate(transform, M_PI_2, 1, 0, 0);
[self addFace:2 withTransform:transform];
}
@end
運(yùn)行效果:
從這個(gè)角度看正方體并不是很明顯珊佣,看起來(lái)只是一個(gè)方塊,為了更好地欣賞它披粟,我們將更換一個(gè)不同的視角
但是旋轉(zhuǎn)這個(gè)正方體將會(huì)顯得很笨重咒锻,因?yàn)槲覀円獑为?dú)對(duì)每個(gè)面做旋轉(zhuǎn),這時(shí)候我們之前說(shuō)的sublayerTransform就派上了用場(chǎng)
添加兩行代碼去旋轉(zhuǎn)containerView圖層的perspective變換矩陣:
perspective = CATransform3DRotate(perspective, -M_PI_4, 1, 0, 0);
perspective = CATransform3DRotate(perspective, -M_PI_4, 0, 1, 0);
把相機(jī)(或者相對(duì)相機(jī)的整個(gè)場(chǎng)景)繞Y軸旋轉(zhuǎn)45度守屉,并且繞X軸旋轉(zhuǎn)45度惑艇,現(xiàn)在從另一個(gè)角度去觀察正方體,就能看出它的真實(shí)面貌:
效果出來(lái)了拇泛,但是我還想旋轉(zhuǎn)一下這個(gè)正方體滨巴,看看其他的面,怎么辦呢
so easy俺叭!繞y軸旋轉(zhuǎn)咯
說(shuō)干就干恭取,修改代碼:
#import "TestViewController.h"
@interface TestViewController ()
@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nonatomic, strong) IBOutletCollection(UIView) NSArray *faces;
@end
@implementation TestViewController{
CATransform3D rotateTransform;
}
- (void)addFace:(NSInteger)index withTransform:(CATransform3D)transform{
//get the face view and add it to the container
UIView *face = self.faces[index];
[self.containerView addSubview:face];
//center the face view within the container
CGSize containerSize = self.containerView.bounds.size;
face.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0);
// apply the transform
face.layer.transform = transform;
}
- (void)viewDidLoad{
[super viewDidLoad];
//set up the container sublayer transform
rotateTransform = CATransform3DIdentity;
rotateTransform.m34 = -1.0f / 500.0f;
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0 / 500.0;
perspective = CATransform3DRotate(perspective, -M_PI_4, 1, 0, 0);
perspective = CATransform3DRotate(perspective, -M_PI_4, 0, 1, 0);
self.containerView.layer.sublayerTransform = perspective;
//add cube face 1
CATransform3D transform = CATransform3DMakeTranslation(0, 0, 100);
[self addFace:0 withTransform:transform];
//add cube face 2
transform = CATransform3DMakeTranslation(100, 0, 0);
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
[self addFace:1 withTransform:transform];
//add cube face 3
transform = CATransform3DMakeTranslation(0, -100, 0);
transform = CATransform3DRotate(transform, M_PI_2, 1, 0, 0);
[self addFace:2 withTransform:transform];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[NSTimer scheduledTimerWithTimeInterval:0.01f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
}
-(void)timerAction{
static CGFloat angle = 1.0f;
rotateTransform = CATransform3DRotate(rotateTransform, angle/180.0f*M_PI, 0.0f, 1.0f, 0.0f);
self.containerView.layer.transform = rotateTransform;
}
@end
跑起來(lái):
納尼,這是什么鬼??
這是由于盡管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)景僅僅是被繪制在圖層的表面牍氛。
總之一句話,圖層是扁平的烟阐,直接把superLayer繞y軸旋轉(zhuǎn)的方法行不通
要想實(shí)現(xiàn)旋轉(zhuǎn)正方體的效果搬俊,就得將所有的子圖層全部挨個(gè)兒做變換
到最后還得用sublayerTransform
繼續(xù)修改代碼:
#import "TestViewController.h"
@interface TestViewController ()
@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nonatomic, strong) IBOutletCollection(UIView) NSArray *faces;
@end
@implementation TestViewController{
// CATransform3D rotateTransform;
}
- (void)addFace:(NSInteger)index withTransform:(CATransform3D)transform{
//get the face view and add it to the container
UIView *face = self.faces[index];
[self.containerView addSubview:face];
//center the face view within the container
CGSize containerSize = self.containerView.bounds.size;
face.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0);
// apply the transform
face.layer.transform = transform;
}
- (void)viewDidLoad{
[super viewDidLoad];
//set up the container sublayer transform
// rotateTransform = CATransform3DIdentity;
// rotateTransform.m34 = -1.0f / 500.0f;
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0 / 500.0;
perspective = CATransform3DRotate(perspective, -M_PI_4, 1, 0, 0);
perspective = CATransform3DRotate(perspective, -M_PI_4, 0, 1, 0);
self.containerView.layer.sublayerTransform = perspective;
//add cube face 1
CATransform3D transform = CATransform3DMakeTranslation(0, 0, 100);
[self addFace:0 withTransform:transform];
//add cube face 2
transform = CATransform3DMakeTranslation(100, 0, 0);
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
[self addFace:1 withTransform:transform];
//add cube face 3
transform = CATransform3DMakeTranslation(0, -100, 0);
transform = CATransform3DRotate(transform, M_PI_2, 1, 0, 0);
[self addFace:2 withTransform:transform];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[NSTimer scheduledTimerWithTimeInterval:0.01f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
}
-(void)timerAction{
static CGFloat angle = 1.0f;
CATransform3D transform3d = self.containerView.layer.sublayerTransform;
transform3d = CATransform3DRotate(transform3d, angle/180.0f*M_PI, 0.0f, 1.0f, 0.0f);
self.containerView.layer.sublayerTransform = transform3d;
// rotateTransform = CATransform3DRotate(rotateTransform, angle/180.0f*M_PI, 0.0f, 1.0f, 0.0f);
// self.containerView.layer.transform = rotateTransform;
}
@end
最終運(yùn)行效果: