• IOS Core Animation Advanced Techniques的学习笔记(四)


    第五章:Transforms

     
    Affine Transforms
     
    CGAffineTransform是二维的
     
     
    Creating a CGAffineTransform
     
    主要有三种变化方法
    旋转:
    CGAffineTransformMakeRotation(CGFloat angle)
     
     
    缩放:
    CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
     

    移动:
    CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
     
     
     

    例子5.1 CGAffineTransformMakeRotation

    源码在这里下载:http://www.informit.com/title/9780133440751

    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
    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
    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
    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
    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);

     
    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);
    代码:
    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又是一个结构。他有自己的一个公式,可以进行套用。

    struct CATransform3D

    {

        CGFloat     m11(x缩放),    m12(y切变),    m13(旋转),     m14( );

        CGFloat     m21(x切变),    m22(y缩放),    m23( ),           m24( );

        CGFloat     m31(旋转),      m32( ),           m33( ),            m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。正直/负值都有意义);

        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

    }

     

     

    1. CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);  
    2. transform.m11 = 2;  

    或者修改键值

     

    1. [myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"];  
     
     
    例子5.4
    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
     
    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
    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  


     
    如果修改注释掉旋转,看看会有什么结果
    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
    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文件,并修改代码
    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°)
    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设置
    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
  • 相关阅读:
    H5 移动端,keyup,keydown,keypress IOS系统无响应
    JS点击图片放大
    windows设备相关位图与设备无关位图
    windows gdi+ Bitmap 总结
    长假无聊的结果:开机时间提示,进程绞杀
    JavaScript通过递归实现深拷贝
    Javascript高级程序设计第七章 | ch7 | 阅读笔记
    修改原型链之后,旧对象仍旧指向原先的原型链
    箭头函数this指向问题
    javascript 类class设置访问器setter时出现Maximum call stack size exceeded错误
  • 原文地址:https://www.cnblogs.com/lzlsky/p/4011822.html
Copyright © 2020-2023  润新知