美文网首页
iOS Core Animation Advanced Tech

iOS Core Animation Advanced Tech

作者: Helly1024 | 来源:发表于2016-04-13 17:44 被阅读96次

    变换

    仿射变换

    CGAffineTransform是一个可以和二维空间向量(如CGPoint)做乘法的3*2的矩阵。当对图层应用变换矩阵,图层内的每一个点都被相应地做变换,从而形成一个新的四边形的形状。CGAffineTransform中仿射的意思是无论变换矩阵用什么值,图层中平行的两条线在变换后任然保持平行。

    UIView可以通过设置transform属性做变换,但实际上它只是封装了内部图层的变换。CALayer同样也有一个transform属性,但它的类型是CATransform3D,而不是CGAffineTransform。CALayer对应于UIView的transform属性叫做affineTransform

    CGAffineTransformMakeRotation(CGFloat angle)              // 旋转
    CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)        // 缩放
    CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)  // 平移
    

    由于iOS变换函数使用弧度而不是角度作为单位,所以做旋转变换的时候可以使用如下宏来将角度换算成弧度:

    #define RADIANS_TO_DEGREES(x) ((x)/M_PI*180.0)
    

    混合变换

    混合变换函数:

    CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
    CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
    CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
    CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2)
    

    当生成一个混合变换的时候,首先需要创建一个CGAffineTransform类型的空值,矩阵论中称为单位矩阵,Core Graphics 中提供了一个方便的常量:

    CGAffineTransformIdentity
    

    如果需要混合两个已经存在的变换矩阵,就可以使用如下方法,在两个变换的基础上创建一个新的变换:

    CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);
    

    示例代码:

    - (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;
    }
    

    3D变换

    CATransform3D是一个可以在3维空间内做变换的4*4的矩阵。和CGAffineTransform矩阵类似,Core Animation提供了一系列的方法用来创建和组合CATransform3D类型的矩阵,和Core Graphics的函数类似,但是3D的平移和旋转多处了一个z参数,并且旋转函数除了angle之外多出了x,y,z三个参数,分别决定了每个坐标轴方向上的旋转:

    CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
    CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz) 
    CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)
    

    绕Z轴的旋转等同于之前二维空间的仿射旋转,但是绕X轴和Y轴的旋转就突破了屏幕的二维空间,并且在用户视角看来发生了倾斜。

    如果要实现透视效果,还需要引入投影变换(又称作z变换)来对除了旋转之外的变换矩阵做一些修改,而这可以通过修改矩阵值来实现。CATransform3D中的透视效果通过矩阵中一个很简单的元素来控制:m34m34用于按比例缩放x和y的值来计算到底要离视角多远。

    m34的默认值是0,可以通过设置m34为-1.0/d来应用透视效果。d代表了想象中视角相机和屏幕之间的距离,以像素为单位,通常设置为500-1000。

    @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;
    }
    

    灭点

    灭点是指在透视角度物体远离视角的那端汇聚消失的那个点。在现实中,这个点通常是视图的中心,于是为了在屏幕中创建拟真效果的透视,这个点应该聚在屏幕中点,或者至少是包含所有3D对象的视图中点。

    Core Animation定义了这个点位于变换图层的anchorPoint。这就是说,当图层发生变换时,这个点永远位于图层变换之前anchorPoint的位置。

    当改变一个图层的position,也就改变了它的灭点,做3D变换的时候要时刻记住这一点,当视图通过调整m34来让它更加有3D效果,应该首先把它放置于屏幕中央,然后通过平移来把它移动到指定位置,而不是直接改变它的position,这样所有的3D图层都共享一个灭点。

    sublayerTransform属性

    如果要为多个视图或图层做3D变换并且保证灭点设置在容器图层中心,可以使用CALayer的sublayerTransform属性:

    @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;
    }
    

    禁用背面绘制:

    layer.doubleSided = NO;
    

    固体对象

    示例代码:

    @implementation RootViewController
    
    - (void)viewDidLoad {
        
        [super viewDidLoad];
        
        CATransform3D perspective = CATransform3DIdentity;
        perspective.m34 = -1.0 / 500;
        perspective = CATransform3DRotate(perspective, -M_PI_4, 1, 0, 0);
        perspective = CATransform3DRotate(perspective, -M_PI, 0, 1, 0);
        
        self.containerView.layer.sublayerTransform = perspective;
        
        CATransform3D transform = CATransform3DMakeTranslation(0, 0, 100);
        [self addFace:0 withTransform:transform];
        
        transform = CATransform3DMakeTranslation(100, 0, 0);
        transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
        [self addFace:1 withTransform:transform];
        
        transform = CATransform3DMakeTranslation(-100, 0, 0);
        transform = CATransform3DRotate(transform, -M_PI_2, 0, 1, 0);
        [self addFace:2 withTransform:transform];
        
        transform = CATransform3DMakeTranslation(0, 100, 0);
        transform = CATransform3DRotate(transform, -M_PI_2, 1, 0, 0);
        [self addFace:3 withTransform:transform];
        
        transform = CATransform3DMakeTranslation(0, -100, 0);
        transform = CATransform3DRotate(transform, M_PI_2, 1, 0, 0);
        [self addFace:4 withTransform:transform];
        
        transform = CATransform3DMakeTranslation(0, 0, -100);
        transform = CATransform3DRotate(transform, M_PI, 0, 1, 0);
        [self addFace:5 withTransform:transform];
    }
    
    - (void)addFace:(NSInteger)index withTransform:(CATransform3D)transfrom {
    
        UIView *view = self.faces[index];
        
        [self.containerView addSubview:view];
        
        view.center = self.containerView.center;
        
        view.layer.transform = transfrom;
        view.layer.borderWidth = 1.0f;
    }

    相关文章

      网友评论

          本文标题:iOS Core Animation Advanced Tech

          本文链接:https://www.haomeiwen.com/subject/ulxglttx.html