zoukankan      html  css  js  c++  java
  • 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

    @interface ViewController ()
    
    @property (nonatomic, weak) IBOutlet UIView *layerView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	
        //rotate the layer 45 degrees
        CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);
        self.layerView.layer.affineTransform = transform;
    }
    
    @end
    


    改动 CGAffineTransformMakeScale
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	
        //rotate the layer 45 degrees
        CGAffineTransform transform = CGAffineTransformMakeScale(0.5, 0.5);
        self.layerView.layer.affineTransform = transform;
    }
    


    改动   CGAffineTransformMakeTranslation
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	
        //rotate the layer 45 degrees
        CGAffineTransform transform = CGAffineTransformMakeTranslation(-50.0, 30.0);
        self.layerView.layer.affineTransform = transform;
    }
    




    Combining Transforms

    方法1:使用CGAffineTransformConcat

    继续改动样例5.1
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	
        //rotate the layer 45 degrees
        CGAffineTransform transform1 = CGAffineTransformMakeRotation(M_PI_4);
        CGAffineTransform transform2 = CGAffineTransformMakeScale(0.5, 0.5);
        CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);
        self.layerView.layer.affineTransform = transform;
    }
    


    方法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
    @interface ViewController ()
    
    @property (nonatomic, weak) IBOutlet UIView *layerView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	
        //create a new transform
        CGAffineTransform transform = CGAffineTransformIdentity;
        
        //scale by 50%
        transform = CGAffineTransformScale(transform, 0.5, 0.5);
        
        //rotate by 30 degrees
        transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 30.0);
        
        //translate by 200 points
        transform = CGAffineTransformTranslate(transform, 200, 0);
        
        //apply transform to layer
        self.layerView.layer.affineTransform = transform;
    }
    
    @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);
    代码:
    @interface ViewController ()
    
    @property (nonatomic, weak) IBOutlet UIView *layerView;
    
    @end
    
    @implementation ViewController
    
    CGAffineTransform CGAffineTransformMakeShear(CGFloat x, CGFloat y)
    {
        CGAffineTransform transform = CGAffineTransformIdentity;
        transform.c = -x;
        transform.b = y;
        return transform;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	
        //shear the layer at a 45-degree angle
        self.layerView.layer.affineTransform = CGAffineTransformMakeShear(1, 0);
    }
    
    @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)

    sxX轴缩放,代表一个缩放比例,一般都是0 ---1之间的数字。

    syY轴缩放。

    sz:总体比例变换时,也就是m11(sx) == m22(sy)时。若m33(sz)>1,图形总体缩小。

            若< m33(sz) 1,图形总体放大,

            若m33(sz) 0。发生关于原点的对称等比变换。


    sx = 1sy =1时。如图:


    sx = 0.5sy =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

    竖起来看相应前面的数据结构就非常明显了。


    txX轴偏移位置。往下为正数。

    tyY轴偏移位置。往右为正数。

    tzZ轴偏移位置。往外为正数。



    能够通过直接改动数据结构。来设置变换效果

    struct CATransform3D

    {

        CGFloat m11, m12, m13, m14

        CGFloat m21, m22, m23, m24

        CGFloat m31, m32, m33, m34

        CGFloat m41, m42, m43, m44

    }

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

    或者改动键值

        [myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"];




    样例5.4
    @interface ViewController ()
    
    @property (nonatomic, weak) IBOutlet UIView *layerView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	
        //rotate the layer 45 degrees along the Y axis
        CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
        self.layerView.layer.transform = transform;
    }
    
    @end
    


    改动样例5.4,改动自http://lepetit-prince.net/ios/?p=451

    #import "ViewController.h"
    #import <QuartzCore/QuartzCore.h>
    
    @interface ViewController ()
    {
        BOOL front;
    }
    
    @property (nonatomic, weak) IBOutlet UIView *layerView;
    
    @end
    
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        front = YES;
    
        self.layerView.layer.contents = (__bridge id)([UIImage imageNamed:@"front.png"].CGImage);
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [UIView animateWithDuration:0.5 animations:^{
            self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 0.5, 0.0f, 1.0f, 0.0f);
        } completion:^(BOOL finished) {
            self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 1.5, 0.0f, 1.0f, 0.0f);
    
            self.layerView.layer.contents = front ?

    (__bridge id)([UIImage imageNamed:@"back.png"].CGImage) : (__bridge id)([UIImage imageNamed:@"front.png"].CGImage); [UIView animateWithDuration:0.5 animations:^{ self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 2, 0.0f, 1.0f, 0.0f); } completion:^(BOOL finished) { front = !front; }]; }]; } @end

    资源文件 front.png    back.png



    Perspective Projection

    前面提到过m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。

    正直/负值都有意义)


    样例5.5
    @interface ViewController ()
    
    @property (nonatomic, weak) IBOutlet UIView *layerView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        //create a new transform
        CATransform3D transform = CATransform3DIdentity;
        
        //apply perspective
        transform.m34 = - 1.0 / 500.0;
    	
        //rotate by 45 degrees along the Y axis
        transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
        
        //apply to layer
        self.layerView.layer.transform = transform;
    }
    
    @end
    


    假设改动凝视掉旋转,看看会有什么结果
        //rotate by 45 degrees along the Y axis
        //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
    @interface ViewController ()
    
    @property (nonatomic, weak) IBOutlet UIView *containerView;
    @property (nonatomic, weak) IBOutlet UIView *layerView1;
    @property (nonatomic, weak) IBOutlet UIView *layerView2;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        //apply perspective transform to container
        CATransform3D perspective = CATransform3DIdentity;
        perspective.m34 = - 1.0 / 500.0;
        self.containerView.layer.sublayerTransform = perspective;
    	
        //rotate layerView1 by 45 degrees along the Y axis
        CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
        self.layerView1.layer.transform = transform1;
        
        //rotate layerView2 by 45 degrees along the Y axis
        CATransform3D transform2 = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);
        self.layerView2.layer.transform = transform2;
    }
    
    @end
    


    我们挪动一下xib里的图片位置:

    再看结果


    恢复xib文件,并改动代码
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        //apply perspective transform to container
    //    CATransform3D perspective = CATransform3DIdentity;
    //    perspective.m34 = - 1.0 / 500.0;
    //    self.containerView.layer.sublayerTransform = perspective;
    
        //apply perspective
        CATransform3D transform1 = CATransform3DIdentity;
        transform1.m34 = - 1.0 / 500.0;
        transform1 = CATransform3DRotate(transform1, M_PI_4, 0, 1, 0);
        self.layerView1.layer.transform = transform1;
        
        //rotate layerView2 by 45 degrees along the Y axis
        CATransform3D transform2 = CATransform3DIdentity;
        transform2.m34 = - 1.0 / 500.0;
        transform2 = CATransform3DRotate(transform2, -M_PI_4, 0, 1, 0);
        self.layerView2.layer.transform = transform2;
    }
    


    结果和最初一样,但再次改动xib文件。挪动图片看结果,比較未改代码时的效果


    大家发现设置sublayerTransform的优点了吗

    1. 能够一次设置全部subLayer的变换效果
    2. Vanishing Point(灭点)被同一时候设置在container layer即父图层的中心,这就意味着不管你怎么
        改动subLayer的position或frame,它们都会保持一个同样的灭点。


    Backfaces

    样例5.4。我们设置的是旋转M_PI_4(45°),改为M_PI(180°)
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	
        //rotate the layer 45 degrees along the Y axis
        CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
        self.layerView.layer.transform = transform;
    }
    


    翻到了layer背面,显示的是原图像的镜像图。由此可见layer是双面的。而且两面都被描绘了。
    因此我们会想到,为什么要浪费GPU去描绘我们看不见的部分呢。

    CALayer的另外一个属性

    doubleSided能够解决问题。


    在刚才改动过的样例5.4的代码中添加doubleSided设置
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	
        //rotate the layer 45 degrees along the Y axis
        CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
        self.layerView.layer.transform = transform;
        self.layerView.layer.doubleSided = NO;
    }
    

    图像没有了



    Layer Flattening
    自己看样例吧。样例5.7和5.8


    Solid Objects
    也自己看样例吧,样例5.9和5.10






  • 相关阅读:
    【SCOI2012】滑雪
    【NOI2008】假面舞会
    ※初赛知识总结※
    【FJSC2012】足球
    【中山市选2011】杀人游戏
    【SDOI2008】洞穴勘测
    【SNOI2017】炸弹
    【LGOJ1606】白银莲花池
    int类型中为什么负数比正数多了一个数?
    utf8、utf16、utf32之间的格式
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/9962039.html
Copyright © 2011-2022 走看看