當咱們在構造複雜的3D事物的時候,若是可以組織獨立元素就太方便了。好比說,你想創造一個孩子的手臂:你就須要肯定哪一部分是孩子的手腕,哪一部分是孩子的前臂,哪一部分是孩子的肘,哪一部分是孩子的上臂,哪一部分是孩子的肩膀等等。app
固然是容許獨立地移動每一個區域的啦。以肘爲指點會移動前臂和手,而不是肩膀。Core Animation圖層很容易就可讓你在2D環境下作出這樣的層級體系下的變換,可是3D狀況下就不太可能,由於全部的圖層都把他的孩子都平面化到一個場景中。dom
CATransformLayer解決了這個問題,CATransformLayer不一樣於普通的CALayer,由於它不能顯示它本身的內容。只有當存在了一個能做用域子圖層的變換它才真正存在。CATransformLayer並不平面化它的子圖層,因此它可以用於構造一個層級的3D結構,好比個人手臂示例。atom
用代碼建立一個手臂須要至關多的代碼,因此我就演示得更簡單一些吧:在圖形變換中的例子的立方體示例,咱們將經過旋轉camara來解決圖層平面化問題而不是像立方體示例代碼中用的sublayerTransform。這是一個很是不錯的技巧,可是隻能做用域單個對象上,若是你的場景包含兩個立方體,那咱們就不能用這個技巧單獨旋轉他們了。spa
那麼,就讓咱們來試一試CATransformLayer吧,第一個問題就來了:在以前的例子中,咱們是用多個視圖來構造了咱們的立方體,而不是單獨的圖層。咱們不能在不打亂已有的視圖層次的前提下在一個自己不是有寄宿圖的圖層中放置一個寄宿圖圖層。咱們能夠建立一個新的UIView子類寄宿在CATransformLayer(用+layerClass方法)之上。可是,爲了簡化案例,咱們僅僅重建了一個單獨的圖層,而不是使用視圖。這意味着咱們不能像第五章同樣在立方體表面顯示按鈕和標籤,不過咱們如今也用不到這個特性。code
咱們以咱們在第五章使用過的相同基本邏輯放置立方體。可是並不像之前那樣直接將立方面添加到容器視圖的宿主圖層,咱們將他們放置到一個CATransformLayer中建立一個獨立的立方體對象,而後將兩個這樣的立方體放進容器中。咱們隨機地給立方面染色以將他們區分開來,這樣就不用靠標籤或是光亮來區分他們。
orm
// // Transform3DViewController.m // iOSanimation // // Created by biyabi on 15/10/25. // Copyright © 2015年 caijunrong. All rights reserved. // #import "Transform3DViewController.h" #import <GLKit/GLKit.h> @interface Transform3DViewController () @property (nonatomic, weak) IBOutlet UIView *contianVIew; @property (nonatomic, strong) IBOutletCollection(UIView) NSArray *faces; @end @implementation Transform3DViewController - (void)viewDidLoad { [super viewDidLoad]; //使用sublayer來完成 // [self Transform3DOne]; //使用CATransformlayer來完成 [self Transform3DTwo]; } - (void)Transform3DTwo{ //set up the perspective transform CATransform3D pt = CATransform3DIdentity; pt.m34 = -1.0 / 500.0; self.view.layer.sublayerTransform = pt; //set up the transform for cube 1 and add it CATransform3D c1t = CATransform3DIdentity; c1t = CATransform3DTranslate(c1t, -100, 0, 0); c1t = CATransform3DRotate(c1t, -M_PI_4, 0, 1, 1); c1t = CATransform3DRotate(c1t, M_PI_2, 1, 0, 0); CALayer *cube1 = [self cubeWithTransform:c1t]; [self.view.layer addSublayer:cube1]; //set up the transform for cube 2 and add it CATransform3D c2t = CATransform3DIdentity; c2t = CATransform3DTranslate(c2t, 100, 0, 0); c2t = CATransform3DRotate(c2t, -M_PI_4, 1, 0, 0); c2t = CATransform3DRotate(c2t, -M_PI_4, 0, 1, 0); CALayer *cube2 = [self cubeWithTransform:c2t]; [self.view.layer addSublayer:cube2]; } - (CALayer *)faceWithTransform:(CATransform3D)transform { //create cube face layer CALayer *face = [CALayer layer]; face.frame = CGRectMake(-50, -50, 100, 100); //apply a random color CGFloat red = (rand() / (double)INT_MAX); CGFloat green = (rand() / (double)INT_MAX); CGFloat blue = (rand() / (double)INT_MAX); face.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor; face.transform = transform; return face; } - (CALayer *)cubeWithTransform:(CATransform3D)transform { //create cube layer CATransformLayer *cube = [CATransformLayer layer]; //add cube face 1 CATransform3D ct = CATransform3DMakeTranslation(0, 0, 50); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 2 ct = CATransform3DMakeTranslation(50, 0, 0); ct = CATransform3DRotate(ct, M_PI_2, 0, 1, 0); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 3 ct = CATransform3DMakeTranslation(0, -50, 0); ct = CATransform3DRotate(ct, M_PI_2, 1, 0, 0); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 4 ct = CATransform3DMakeTranslation(0, 50, 0); ct = CATransform3DRotate(ct, -M_PI_2, 1, 0, 0); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 5 ct = CATransform3DMakeTranslation(-50, 0, 0); ct = CATransform3DRotate(ct, -M_PI_2, 0, 1, 0); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 6 ct = CATransform3DMakeTranslation(0, 0, -50); ct = CATransform3DRotate(ct, M_PI, 0, 1, 0); [cube addSublayer:[self faceWithTransform:ct]]; //center the cube layer within the container CGSize containerSize = self.view.bounds.size; cube.position = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0); //apply the transform and return cube.transform = transform; return cube; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end