IOS Core Animation Advanced Techniques的學習筆記(四)

第五章:Transformsios

 
Affine Transforms
 
CGAffineTransform是二維的
 
 
Creating a CGAffineTransform
 
主要有三種變化方法
旋轉:
CGAffineTransformMakeRotation(CGFloat angle)
 
 
縮放:
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
 

移動:
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
 
 
 

例子5.1 CGAffineTransformMakeRotationxcode

源碼在這裏下載:http://www.informit.com/title/9780133440751數據結構

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. @interface ViewController ()  
  2.   
  3. @property (nonatomic, weak) IBOutlet UIView *layerView;  
  4.   
  5. @end  
  6.   
  7. @implementation ViewController  
  8.   
  9. - (void)viewDidLoad  
  10. {  
  11.     [super viewDidLoad];  
  12.       
  13.     //rotate the layer 45 degrees  
  14.     CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);  
  15.     self.layerView.layer.affineTransform = transform;  
  16. }  
  17.   
  18. @end  


 
修改 CGAffineTransformMakeScale
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     //rotate the layer 45 degrees  
  6.     CGAffineTransform transform = CGAffineTransformMakeScale(0.5, 0.5);  
  7.     self.layerView.layer.affineTransform = transform;  
  8. }  


修改   CGAffineTransformMakeTranslation
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     //rotate the layer 45 degrees  
  6.     CGAffineTransform transform = CGAffineTransformMakeTranslation(-50.0, 30.0);  
  7.     self.layerView.layer.affineTransform = transform;  
  8. }  


 
 
 
Combining Transforms
 
方法1:使用CGAffineTransformConcat
 
繼續修改例子5.1
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     //rotate the layer 45 degrees  
  6.     CGAffineTransform transform1 = CGAffineTransformMakeRotation(M_PI_4);  
  7.     CGAffineTransform transform2 = CGAffineTransformMakeScale(0.5, 0.5);  
  8.     CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);  
  9.     self.layerView.layer.affineTransform = transform;  
  10. }  


 
方法2:
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
和前面的CGAffineTransformMakeRotation函數相同,也能夠混用
CGAffineTransform t能夠使用CGAffineTransformIdentity函數初始化
 
例子5.2
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. @interface ViewController ()  
  2.   
  3. @property (nonatomic, weak) IBOutlet UIView *layerView;  
  4.   
  5. @end  
  6.   
  7. @implementation ViewController  
  8.   
  9. - (void)viewDidLoad  
  10. {  
  11.     [super viewDidLoad];  
  12.       
  13.     //create a new transform  
  14.     CGAffineTransform transform = CGAffineTransformIdentity;  
  15.       
  16.     //scale by 50%  
  17.     transform = CGAffineTransformScale(transform, 0.5, 0.5);  
  18.       
  19.     //rotate by 30 degrees  
  20.     transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 30.0);  
  21.       
  22.     //translate by 200 points  
  23.     transform = CGAffineTransformTranslate(transform, 200, 0);  
  24.       
  25.     //apply transform to layer  
  26.     self.layerView.layer.affineTransform = transform;  
  27. }  
  28.   
  29. @end  


 
 
下面記幾個特殊值
1. 首先要知道函數 CGAffineTransformIdentity 初始化的結果
          
 
2. 左右翻轉
    CGAffineTransformMake (-1,0,0,1,0,0);

 
3. 以右邊爲軸向右翻轉
     CGAffineTransformMake(-1,0,0,1,self.layerView.frame.size.width,0);

 
4. 上下翻轉

    CGAffineTransformMake(1,0,0, -1,0,0);app

 
5. 以底邊爲軸向下翻轉
    CGAffineTransformMake (1,0,0, -1,0,self.layerView.frame.size.height);
 
6. 轉180°
    CGAffineTransformMake (-1,0,0, -1,0,0);
 
7. 例子5.3,向右斜拉
    CGAffineTransformMake (1,0, -1,1,0,0);
代碼:
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. @interface ViewController ()  
  2.   
  3. @property (nonatomic, weak) IBOutlet UIView *layerView;  
  4.   
  5. @end  
  6.   
  7. @implementation ViewController  
  8.   
  9. CGAffineTransform CGAffineTransformMakeShear(CGFloat x, CGFloat y)  
  10. {  
  11.     CGAffineTransform transform = CGAffineTransformIdentity;  
  12.     transform.c = -x;  
  13.     transform.b = y;  
  14.     return transform;  
  15. }  
  16.   
  17. - (void)viewDidLoad  
  18. {  
  19.     [super viewDidLoad];  
  20.       
  21.     //shear the layer at a 45-degree angle  
  22.     self.layerView.layer.affineTransform = CGAffineTransformMakeShear(1, 0);  
  23. }  
  24.   
  25. @end  


 
8. 例子5.3,向左斜拉
    CGAffineTransformMake (10,1100);
 
 
 
3D Transforms
 
相似CGAffineTransform,CATransform3D是三維的
 

CATransform3D又是一個結構。他有本身的一個公式,能夠進行套用。ide

struct CATransform3Dsvg

{函數

    CGFloat     m11(x縮放),    m12(y切變),    m13(旋轉),     m14( );oop

    CGFloat     m21(x切變),    m22(y縮放),    m23( ),           m24( );atom

    CGFloat     m31(旋轉),      m32( ),           m33( ),            m34(透視效果,要操做的這個對象要有旋轉的角度,不然沒有效果。正直/負值都有意義);spa

    CGFloat     m41(x平移),    m42(y平移),    m43(z平移),    m44( );

};

 
一樣有三種變換方法
 
旋轉:
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
首先要先清楚x,y,z是什麼
{x, y, z}組成的向量就是旋轉要使用的軸,angle是旋轉角度
 

 

例:原圖 

             

       向X軸旋轉45度。                               向Y軸旋轉45度。                         向Z軸旋轉45度。

        

 X軸,Y軸都旋轉45度,就是沿着對角線旋轉。

 
 
縮放:
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz)

sx:X軸縮放,表明一個縮放比例,通常都是0 ---1之間的數字。

sy:Y軸縮放。

sz:總體比例變換時,也就是m11(sx) == m22(sy)時,若m33(sz)>1,圖形總體縮小,

        若< m33(sz) 1,圖形總體放大,

        若m33(sz) 0,發生關於原點的對稱等比變換。

 

當sx = 1,sy =1時。如圖:

當sx = 0.5,sy =0.5時。如圖:

 
 
變換:
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)

t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1]

1    0    0    0

0    1    0    0

0    0    1    0

tx   ty    tz   1

豎起來看對應前面的數據結構就很明顯了。

 

tx:X軸偏移位置,往下爲正數。

ty:Y軸偏移位置,往右爲正數。

tz:Z軸偏移位置,往外爲正數。

 

能夠經過直接修改數據結構,來設置變換效果

struct CATransform3D

{

    CGFloat m11, m12, m13, m14

    CGFloat m21, m22, m23, m24

    CGFloat m31, m32, m33, m34

    CGFloat m41, m42, m43, m44

}

 

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);  
  2. transform.m11 = 2;  

 

或者修改鍵值

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. [myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"];  

 

 
 
例子5.4
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. @interface ViewController ()  
  2.   
  3. @property (nonatomic, weak) IBOutlet UIView *layerView;  
  4.   
  5. @end  
  6.   
  7. @implementation ViewController  
  8.   
  9. - (void)viewDidLoad  
  10. {  
  11.     [super viewDidLoad];  
  12.       
  13.     //rotate the layer 45 degrees along the Y axis  
  14.     CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);  
  15.     self.layerView.layer.transform = transform;  
  16. }  
  17.   
  18. @end  


 
修改例子5.4,修改自 http://lepetit-prince.net/ios/?p=451
 
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. #import "ViewController.h"  
  2. #import <QuartzCore/QuartzCore.h>  
  3.   
  4. @interface ViewController ()  
  5. {  
  6.     BOOL front;  
  7. }  
  8.   
  9. @property (nonatomic, weak) IBOutlet UIView *layerView;  
  10.   
  11. @end  
  12.   
  13.   
  14. @implementation ViewController  
  15.   
  16. - (void)viewDidLoad  
  17. {  
  18.     [super viewDidLoad];  
  19.   
  20.     front = YES;  
  21.   
  22.     self.layerView.layer.contents = (__bridge id)([UIImage imageNamed:@"front.png"].CGImage);  
  23. }  
  24.   
  25. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  
  26. {  
  27.     [UIView animateWithDuration:0.5 animations:^{  
  28.         self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 0.5, 0.0f, 1.0f, 0.0f);  
  29.     } completion:^(BOOL finished) {  
  30.         self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 1.5, 0.0f, 1.0f, 0.0f);  
  31.   
  32.         self.layerView.layer.contents = front ? (__bridge id)([UIImage imageNamed:@"back.png"].CGImage) : (__bridge id)([UIImage imageNamed:@"front.png"].CGImage);  
  33.   
  34.         [UIView animateWithDuration:0.5 animations:^{  
  35.             self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 2, 0.0f, 1.0f, 0.0f);  
  36.         } completion:^(BOOL finished) {  
  37.             front = !front;  
  38.         }];  
  39.     }];  
  40. }  
  41.   
  42. @end  
資源文件  front.png     back.png
 
 
Perspective Projection
 
前面提到過m34( 透視效果,要操做的這個對象要有旋轉的角度,不然沒有效果。正直/負值都有意義)
 
例子5.5
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. @interface ViewController ()  
  2.   
  3. @property (nonatomic, weak) IBOutlet UIView *layerView;  
  4.   
  5. @end  
  6.   
  7. @implementation ViewController  
  8.   
  9. - (void)viewDidLoad  
  10. {  
  11.     [super viewDidLoad];  
  12.       
  13.     //create a new transform  
  14.     CATransform3D transform = CATransform3DIdentity;  
  15.       
  16.     //apply perspective  
  17.     transform.m34 = - 1.0 / 500.0;  
  18.       
  19.     //rotate by 45 degrees along the Y axis  
  20.     transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);  
  21.       
  22.     //apply to layer  
  23.     self.layerView.layer.transform = transform;  
  24. }  
  25.   
  26. @end  


 
若是修改註釋掉旋轉,看看會有什麼結果
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. //rotate by 45 degrees along the Y axis  
  2. //transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);  

例子是用的透視場景是±1.0/d,d鏡頭到景物的距離,取值500~1000效果最好,±表明方向
 
 
The Vanishing Point
 
當景物慢慢遠離鏡頭時,隨着愈來愈小最終彙集到一點就是Vanishing Point(滅點)
 
一般狀況滅點是在視圖的正中心,或者在包含全部景物範圍的中心。
 
Core Animation把滅點定義在anchorPoint,因此在變換前須要肯定anchorPoint,
尤爲須要注意,3D變換時最好確保同一視圖內的全部layey有相同的滅點
 
 
The sublayerTransform Property
 
若是你有多個View或Layer有相同的3D變換,就能夠使用sublayerTransform,

sublayerTransform也是CATransform3D,只有sublayers纔會響應。

默認值是Identity Transform(CATransform3DIdentity)

例子5.6
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. @interface ViewController ()  
  2.   
  3. @property (nonatomic, weak) IBOutlet UIView *containerView;  
  4. @property (nonatomic, weak) IBOutlet UIView *layerView1;  
  5. @property (nonatomic, weak) IBOutlet UIView *layerView2;  
  6.   
  7. @end  
  8.   
  9. @implementation ViewController  
  10.   
  11. - (void)viewDidLoad  
  12. {  
  13.     [super viewDidLoad];  
  14.       
  15.     //apply perspective transform to container  
  16.     CATransform3D perspective = CATransform3DIdentity;  
  17.     perspective.m34 = - 1.0 / 500.0;  
  18.     self.containerView.layer.sublayerTransform = perspective;  
  19.       
  20.     //rotate layerView1 by 45 degrees along the Y axis  
  21.     CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);  
  22.     self.layerView1.layer.transform = transform1;  
  23.       
  24.     //rotate layerView2 by 45 degrees along the Y axis  
  25.     CATransform3D transform2 = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);  
  26.     self.layerView2.layer.transform = transform2;  
  27. }  
  28.   
  29. @end  


咱們挪動一下xib裏的圖片位置:
再看結果
 
恢復xib文件,並修改代碼
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     //apply perspective transform to container  
  6. //    CATransform3D perspective = CATransform3DIdentity;  
  7. //    perspective.m34 = - 1.0 / 500.0;  
  8. //    self.containerView.layer.sublayerTransform = perspective;  
  9.   
  10.     //apply perspective  
  11.     CATransform3D transform1 = CATransform3DIdentity;  
  12.     transform1.m34 = - 1.0 / 500.0;  
  13.     transform1 = CATransform3DRotate(transform1, M_PI_4, 0, 1, 0);  
  14.     self.layerView1.layer.transform = transform1;  
  15.       
  16.     //rotate layerView2 by 45 degrees along the Y axis  
  17.     CATransform3D transform2 = CATransform3DIdentity;  
  18.     transform2.m34 = - 1.0 / 500.0;  
  19.     transform2 = CATransform3DRotate(transform2, -M_PI_4, 0, 1, 0);  
  20.     self.layerView2.layer.transform = transform2;  
  21. }  


結果和最初同樣,但再次修改xib文件,挪動圖片看結果,比較未改代碼時的效果
 
 
你們發現設置sublayerTransform的好處了嗎
 
1. 能夠一次設置全部subLayer的變換效果
2. Vanishing Point(滅點)被同時設置在container layer即父圖層的中心,這就意味着不管你怎麼
    修改subLayer的position或frame,它們都會保持一個相同的滅點。
 
 
Backfaces
 
例子5.4,咱們設置的是旋轉M_PI_4(45°),改成M_PI(180°)
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     //rotate the layer 45 degrees along the Y axis  
  6.     CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);  
  7.     self.layerView.layer.transform = transform;  
  8. }  


 
翻到了layer背面,顯示的是原圖像的鏡像圖。因而可知layer是雙面的,而且兩面都被描繪了。
所以咱們會想到,爲何要浪費GPU去描繪咱們看不見的部分呢。CALayer的另一個屬性
doubleSided能夠解決這個問題。
在剛纔修改過的例子5.4的代碼中增長doubleSided設置
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     //rotate the layer 45 degrees along the Y axis  
  6.     CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);  
  7.     self.layerView.layer.transform = transform;  
  8.     self.layerView.layer.doubleSided = NO;  
  9. }  

圖像沒有了
 
 
 
 
Layer Flattening
本身看例子吧,例子5.7和5.8
 
 
Solid Objects
也本身看例子吧,例子5.9和5.10
相關文章
相關標籤/搜索