IOS开发—CATransform3D介绍

最近项目中用到CATransform3D实现动画效果,感觉有点力不从心,对CALayer的一些属性模棱两可,故做了一番整理。

首先要知道的几个概念:

1、三维坐标系:视角垂直与屏幕而言,x轴向右,y轴向下,z轴垂直屏幕向外。

2、坐标系原点:ios默认以图层的左上角点为坐标原点,osx默认以图层左下角为坐标原点。注意是默认,因为图层的坐标原点是可以设置的,下面会介绍。

3、view于layer的关系:对于UIView对象,layer属性承担了显示的职能,对view设置frame和bounds就是对view的layer设置,因此下面将不区分view和layer。

4、图层的锚点anchorPoint:是一个CGPoint值,x,y取值范围(0~1),默认为(0.5,0.5) 对于图层本身而言,顾名思义,锚点就用来定位图层的点。锚点有两个职能:(1)与position一同确定图层相对于父图层的位置;(2)作为图层旋转、平移、缩放的中心。

5、决定图层位置的position:图层的锚点相对于父图层坐标系原点的偏移。

6、frame和bounds:这是不太容易拎清的两个属性。frame决定图层在父图层坐标系中的位置和大小,设置frame会改变图层的position和bounds,例如设置frame为CGRectMake(20, 20, 200, 100),不另外设置anchorPoint(默认为(0.5,0.5))position以及bounds,那么这个图层的position为(20+200/2.0,20+100/2.0),bounds为(0,0,200,100)。因此frame的x和y并不是position的x和y,这点需要注意;bounds决定图层在本地坐标系中的位置和大小,即决定图层的坐标原点和大小。因此对一个图层设置bounds会影响其本身的大小,但不会影响其本身在父图层中的位置,影响是子图层的位置,因为子图层的位置是以其坐标原点为参照的。需要注意的是,假如对一个图层设置了bounds为CGRectMake(20, 20, 200, 100),并不是将当前图层的坐标原点相对于图层左上角偏移了(20,20),而是将图层左上角点的坐标设置成了(20,20),本地坐标系的坐标原点偏移了(-20,-20)。因此,要想使本地坐标系的坐标原点偏移(20,20),bounds的x,y应当设置为-20。

    self.superLayer = [CALayer layer];
    self.superLayer.frame = CGRectMake(0, 0, 200, 100);
    self.superLayer.bounds = CGRectMake(-20, -20, 200, 100);
    self.superLayer.backgroundColor = [UIColor orangeColor].CGColor;
    [self.view.layer addSublayer:self.superLayer];

    self.subLayer = [CALayer layer];
    self.subLayer.frame = CGRectMake(0, 0, 100, 50);
    self.subLayer.backgroundColor = [UIColor greenColor].CGColor;
    [self.superLayer addSublayer:self.subLayer];

7、图层的这些属性:frame、bounds、position、anchorPoint,该怎么使用呢?前面介绍过frame会改变图层的position和bounds,因此通常有两种用法:(1)设置frame和bounds(通常只设置frame) (2)设置bounds、position、anchorPoint。什么时候用第(1)种?大多数人都习惯用frame吧。是的,只要在图层的变化(transform)过程中是以图层中心为锚点的,直接用第(1)种用法,即设置frame就好了,因为anchorPoint值为(0.5,0.5)默认为图层中心。如果变化过程不是以图层中心为参照的,比如旋转是以图层左边为旋转轴,那么就要对anchorPoint设置为(0,0.5),这时候就用第(2)种用法。所以为了避免混淆和思路混乱,只要在transform过程中不需要指定图层锚点的,一律用frame就好了。

CATransform3D

CATransform3D(三维变换矩阵)

CATransform3D 的数据结构定义了一个同质的三维变换(4x4 CGFloat值的矩阵),用于图层的旋转,缩放,偏移,歪斜和应用的透视。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();
};

transform

CALayer的属性transform,CATransform3D类型,用于以图层本身的anchorPoint为参考点来对图层本身和图层上的子图层进行变化。

sublayerTransform

CALayer的属性transform,CATransform3D类型,用于以图层本身的anchorPoint为参考点来对图层上的子图层进行变化,不包括图层本身。

CATransform3DIdentity

单位矩阵,该矩阵没有缩放,旋转,歪斜,透视。该矩阵应用到图层上,就是设置默认值。

Translation(平移)

CATransform3D CATransform3DMakeTranslation (CGFloat tx, CGFloat ty, CGFloat tz) 

官方文档:Returns a transform that translates by ‘(tx, ty, tz)’. t’ = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1].即返回一个4x4的矩阵,将该矩阵立起来后看:

1    0    0    0  
0    1    0    0  
0    0    1    0   
tx   ty   tz   1

对应CATransform3D的公式,tx、ty、tz参数分别用于x平移、y平移、z平移。x、y的平移比较好理解,对于tz来说,值越大,那么图层就越往外(接近屏幕),值越小,图层越往里(屏幕里)。
tx:X轴偏移位置,往下为正数。
ty:Y轴偏移位置,往右为正数。
tz:Z轴偏移位置,往外为正数。

CATransform3D CATransform3DTranslate ( CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz );

在t的基础上叠加变换,前面的方法则不能叠加,每次变换都是以起始状态为基础。

Scale(缩放)

CATransform3D CATransform3DMakeScale ( CGFloat sx, CGFloat sy, CGFloat sz );

官方文档L:Returns a transform that scales by `(sx, sy, sz)’: * t’ = [sx 0 0 0; 0 sy 0 0; 0 0 sz 0; 0 0 0 1]. 返回的矩阵为:

sx   0    0    0  
0    sy   0    0  
0    0    sz   0  
0    0    0    1

sx、sy、sz参数对应x、y、z轴的比例缩放,>0为正向比例缩放,<0为反向比例缩放。

CATransform3D CATransform3DScale ( CATransform3D t, CGFloat sx, CGFloat sy, CGFloat sz );

和平移一样,在t 的基础上叠加变换。

Rotation(旋转)

CATransform3D CATransform3DMakeRotation ( CGFloat angle, CGFloat x, CGFloat y, CGFloat z );

angle:旋转的弧度,所以要把角度转换成弧度:角度 * M_PI / 180
x:向X轴方向旋转。值范围-1 — 1之间
y:向Y轴方向旋转。值范围-1 — 1之间
z:向Z轴方向旋转。值范围-1 — 1之间
旋转方向:(当m34为负时)
旋转遵循左手定则。以绕y轴旋转为例,当参数y为正时,左手大拇指指向y轴正向(向下),手掌弯曲方向即为旋转方向,此时从上往下看是逆时针方向。若y参数为父,将大拇指指向y轴负向(向上),此时从上往下看是顺时针方向。 绕x轴z轴旋转判断方法相同。
注意:若m34为正,饶x,y轴旋转遵循右手定则,绕z轴遵循左手定则。

    self.superLayer = [CALayer layer];
    self.superLayer.frame = CGRectMake(100, 200, 200, 100);
    self.superLayer.backgroundColor = [UIColor orangeColor].CGColor;
    [self.view.layer addSublayer:self.superLayer];

    self.myLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
    self.myLabel.backgroundColor = [UIColor greenColor];
    self.myLabel.textAlignment = NSTextAlignmentCenter;
    self.myLabel.text = @"测试";
    self.myLabel.font = [UIFont systemFontOfSize:20.0];
    self.myLabel.textColor = [UIColor purpleColor];
    [self.superLayer addSublayer:self.myLabel.layer];

    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = -1/500.0;
    self.myLabel.layer.transform = transform;

    self.myLabel.layer.transform = CATransform3DRotate(self.myLabel.layer.transform, 60*M_PI/180, 1, 0, 0);//沿x轴正轴旋转60度
//    self.myLabel.layer.transform = CATransform3DRotate(self.myLabel.layer.transform, 60*M_PI/180, 0, 1, 0);//沿y轴正轴旋转60度
//    self.myLabel.layer.transform = CATransform3DRotate(self.myLabel.layer.transform, 60*M_PI/180, 0, 0, 1);//沿z轴正轴旋转60度

CATransform3D CATransform3DRotate ( CATransform3D t, CGFloat angle, CGFloat x, CGFloat y, CGFloat z );

同平移/缩放,理解为效果的叠加。

直接修改矩阵或通过KVC设置变换效果

(1).可以直接修改矩阵的成员变量来得到一个指定的变幻效果。

struct CATransform3D
{
   CGFloat m11, m12, m13, m14;
   CGFloat m21, m22, m23, m24;
   CGFloat m31, m32, m33, m34;
   CGFloat m41, m42, m43, m44;
}

常用的则是对m34赋值,以实现透视投影近大远小的效果。 Ps: m34= -1/D, 默认值是0,也就是说D无穷大,这是看上去没有近大远小的效果,也就是正交投影。D越小,透视效果越明显。

(2).通过KVC对layer直接设置。
例如设置绕x正轴旋转60度:

[self.myLabel.layer setValue:[NSNumber numberWithFloat:60*M_PI/180] forKeyPath:@"transform.rotation.y"];

相关关键字路径如下:

这里写图片描述

其他方法

CATransform3DMakeAffineTransform
CGAffineTransform CATransform3DGetAffineTransform (CATransform3D t);
bool CATransform3DIsAffine (CATransform3D t);

仿射效果。
就是CATransform3D对象和CGAffineTransform对象之间的互相转化。

bool CATransform3DIsIdentity (CATransform3D t);
bool CATransform3DEqualToTransform (CATransform3D a, CATransform3D b);

比较一个变换矩阵是否是单位矩阵,以及两个矩阵是否相等。

参考文档:
《CATransform3D 特效详解》
《CoreAnimation编程指南(三)几何变换》

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值