美文网首页
第四篇:CALayer能力之仿射变换和3D变换

第四篇:CALayer能力之仿射变换和3D变换

作者: 意一ineyee | 来源:发表于2018-01-22 17:07 被阅读51次

    目录

    一、UIView的仿射变换

    1、单仿射变换
    2、混合仿射变换
    3、CGAffineTransformIdentity

    二、CALayer的仿射变换

    三、CALayer的3D变换

    1、单3D变换
    2、混合3D变换
    3、CATransform3DIdentity
    4、3D变换其它

    概述:

    • 所谓变换,就是用来对视图或图层做平移、旋转、缩放操作的,对视图或图层做变换那么视图或图层上的每个点都会做出相应的变换
      • 而仿射和非仿射,是指一个矩形经过变换之后原来平行的两条边是否依然平行,仿射的依然平行,非仿射的不再平行
      • 3D变换是指多了Z轴方向上的一个参数
    • UIView是处于二维坐标系下的,所以它只能做仿射变换;而CALayer是处于三维坐标下的,所以它除了可以做仿射变换之外比UIView多出了一个能力就是还可以做3D变换。因此如果我们想做3D变换,那就只能在layer层做

    一、UIView的仿射变换

    • 声明,UIView的仿射变换也仅仅是对CALayer的仿射变换做了一层封装
    1、单仿射变换

    单仿射变换是指只对视图做某一种类型的变换,平移或者旋转或者缩放。因为view的transform仅仅是一个属性,它只会记录我们最后一个给它赋值的变换类型,所以如果想要实现变换的组合就需要使用下面的混合仿射变换。

    单仿射变换针对平移、旋转、缩放提供了三个方法,如下:

    • CGAffineTransformMakeTranslation(X 轴方向上要平移多少, Y 轴方向上要平移多少);
    • CGAffineTransformMakeScale(X 轴方向上要缩放的比例, Y 轴方向上要缩放的比例);
    • CGAffineTransformMakeRotation(要旋转的角度, 注意是弧度制);

    举例如下:

    self.redView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    self.redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.redView];
    
    // 平移
    self.redView.transform = CGAffineTransformMakeTranslation(100, 100);
    // 旋转
    self.redView.transform = CGAffineTransformMakeRotation(M_PI_4);
    // 缩放
    self.redView.transform = CGAffineTransformMakeScale(2, 2);
    
    2、混合仿射变换

    有的时候我们想对一个视图进行多个变换的组合,那么使用单仿射变换是实现不了的,需要用到混合仿射变换。所谓混合仿射变换,是指我们可以在一个仿射变换的基础上再添加另一个仿射变换。但是需要注意,即便混合仿射变换的组合一样,顺序不一样也会造成不一样的变换效果(比方说先旋转后缩放和先缩放后旋转效果有可能不一样)

    混合仿射变换针对平移、旋转、缩放提供了三个方法,如下:

    • CGAffineTransformTranslate(仿射变换 1, X 轴方向上要平移多少, Y 轴方向上要平移多少);
    • CGAffineTransformScale(仿射变换 1, X 轴方向上要缩放的比例, Y 轴方向上要缩放的比例);
    • CGAffineTransformRotate(仿射变换 1, 要旋转的角度, 注意是弧度制);

    举例如下:

    self.redView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    self.redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.redView];
    
    // 初始化一个什么都不做的变换
    CGAffineTransform transform = CGAffineTransformIdentity;
    // 先平移
    transform = CGAffineTransformTranslate(transform, 100, 100);
    // 后旋转
    transform = CGAffineTransformRotate(transform, M_PI_4);
    // 再缩放
    transform = CGAffineTransformScale(transform, 2, 2);
    
    self.redView.transform = transform;
    
    3、CGAffineTransformIdentity

    此外仿射变换还提供了CGAffineTransformIdentity来表征一个什么都不做的变换

    这样就为单仿射变换和混合仿射变换提供了一个桥梁,只要混合仿射变换的基础变换传入这个什么都不做的变换,就变成了单仿射变换。

    二、CALayer的仿射变换

    前面说了UIView的仿射变换只是对CALayer的仿射变换做了一层封装,所以CALayer的仿射变换和UIView的操作几乎一模一样,所以CALayer的仿射变换就不多做介绍了。

    只是view用来做仿射变换的属性叫transform,而layer的transform属性是用来做3D变换的,所以layer用来做仿射变换的属性换成了affineTransform,其它的完全一样。

    三、CALayer的3D变换

    声明:

    • 我们可以看到UIView和CALayer的仿射变换是”CG“开头的,就是说仿射变换其实是Core Graphics框架下的,Core Graphics框架是专门用来做2D绘图的框架。所以如果我们想要做3D变换,那么就只能在layer层,而我们接下来要学习的3D变换则是属于Quartz Core框架下Core Animation的,以“CA”开头。

    • 3D变换同样是用来对图层进行平移、旋转和缩放的,只不过多了Z轴方向上的一个参数,使用方法基本上和仿射变换一样。

    1、单3D变换

    单3D变换针对平移、旋转、缩放提供了三个方法,如下:

    • CATransform3DMakeTranslation(X 轴方向上要平移多少, X 轴方向上要平移多少, Z 轴方向上要平移多少);
    • CATransform3DMakeRotation(要旋转的角度, 注意是弧度制, 如果绕 X 轴旋转则设为 1 否则设为 0, 同上, 同上); // 绕Z轴的旋转等同于之前二维空间的仿射旋转, 绕X轴和Y轴的旋转就突破了屏幕的二维空间, 并且在用户视角看来会发生倾斜
    • CATransform3DMakeScale(X 轴方向上要缩放的比例, Y 轴方向上要缩放的比例, Z 轴方向上要缩放的比例);

    我们以3D旋转为例:

    // 我们以旋转为例:
    UIView *sourceView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    sourceView.backgroundColor = [UIColor redColor];
    [self.view addSubview:sourceView];
    
    self.redView = [[UIView alloc] initWithFrame:CGRectMake(100, 250, 100, 100)];
    self.redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.redView];
    
    // 绕X轴旋转45度
    self.redView.layer.transform = CATransform3DMakeRotation(M_PI_4, 1, 0, 0);
    
    1.png

    可以看到绕X轴旋转看起来好像没有旋转仅仅是竖向压缩了一点(绕Y轴旋转也是同理),是不是出错了?不是,是因为我们没有模拟现实场景做透视投影的处理,所以看起来好像出错了。

    透视投影

    如果我们直接使用CATransform3DMakeRotation(..., ..., ..., ...);会发现无论是绕X轴还是绕Y轴旋转,结果都好像是压缩了一样,而没有旋转变换的效果。

    其实是进行了旋转变换的,只是因为所有的点都进行了同样的变换,所以原来平行的边还是平行的。而在实际中,经过旋转之后原理我们的那条边应该会看起来短一些,靠近我们的边会看起来长一些。

    所以我们在进行3D旋转时为了达到更模拟实际的透视效果就不能直接使用CAransform3DMakeRotation(..., ..., ..., ...),而是使用组合3D变换的旋转CATransform3DRotate(..., ..., ..., ..., ...),并且设置transform.m34 = - 1.0 / 500.0;来达到远边短近边长的透视效果。修改代码如下:

    // 我们以旋转为例:
    UIView *sourceView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    sourceView.backgroundColor = [UIColor redColor];
    [self.view addSubview:sourceView];
    
    self.redView = [[UIView alloc] initWithFrame:CGRectMake(100, 250, 100, 100)];
    self.redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.redView];
    
    CATransform3D transform = CATransform3DIdentity;
    // 绕X轴旋转45度 + 透视效果
    transform.m34 = - 1.0 / 500;
    transform = CATransform3DRotate(transform, M_PI_4, 1, 0, 0);
    self.redView.layer.transform = transform;
    
    1.png

    可以发现,远离我们的边比较短了,达到了效果。

    2、混合3D变换

    同样的,3D变换也可以组合,类似于组合仿射变换,针对平移、旋转、缩放提供了如下方法:

    • CATransform3DTranslate(3D变换1, X 轴方向上要平移多少, ..., ...);
    • CATransform3DRotate(3D变换1, 要旋转的角度, 注意是弧度制, 如果绕 X 轴旋转则设为 1 否则设为 0, ..., ...);
    • CATransform3DScale(3D变换1, X 轴方向上要缩放的比例, ..., ...);
    3、CATransform3DIdentity

    此外3D变换也提供了CATransform3DIdentity来表征一个什么都不做的变换,这样只要混合3D变换的基础变换只要传入这个什么都不做的变换,就变成了单3D变换。

    4、3D变换其它

    此外,3D变换还有很多其它需要注意和好玩的地方,如灭点(就是一个视图的一个边无限远离我们时,那条边就会缩成一个点,我们称之为灭点,要想达到这样模拟真实的效果,就需要注意)、绘制立方体等等,如果需要可深入学习。

    相关文章

      网友评论

          本文标题:第四篇:CALayer能力之仿射变换和3D变换

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