transform和CATransform3D


UIView的transform属性是CGAffineTransform类型,用于在二维空间做旋转,缩放和平移。
CGAffineTransform是一个可以和二维空间向量做乘法的3 * 2矩阵。如下图:


仿射变换
当对图层应用变换矩阵,图层矩形内的每一个点都被相应的做变换,从而形成一个新的形状。CGAffineTransform仿射变换的仿射意思是无论变换矩阵用什么值,图层中平行的两条线在变换之后仍然保持平行。
看了上边的一些概念,可能觉得雾里云里,不如我们直接上代码和效果。
CGAffineTransform是CG开头的,也就是说是在Core Graphics框架里的,这个框架为我们提供了好用的函数可以让我们不必自己去亲自计算矩阵的相乘。

//常用的三个函数:
CGAffineTransformMakeRotation(CGFloat angle) 
// 旋转 表示旋转多少角度,如果是正数的,会按照顺时针旋转,如果负数,则逆时针旋转。
//注意,这个函数传入的参数不是我们平常说的角度而是弧度。如果觉得分不清楚,或总是混淆的话,可以用下边给出的两个宏做计算。
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
 // 缩放 两个参数分别表示水平方向(x轴)和竖直方向(y轴)的缩放比例。
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)  
// 平移 两个参数分别表示水平方向(x轴)和竖直方向(y轴)上平移的位移(以点`point`计)
//弧度转角度
#define RADIANS_TO_DEGREES(x) ((x)/M_PI*180.0)//传入弧度 eg: M_PI_4
//角度转弧度
#define DEGREES_TO_RADIANS(x) ((x)/180.0*M_PI)//传入度数eg:45度
- (void)test0
{
    ///右转90度
    CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_2);
    
    //以下两个赋值效果一样。最终都是作用于layer上。
    self.label.transform = transform;
//    self.label.layer.affineTransform = transform;
}

- (void)test1
{
    //水平方向缩小0.5倍,竖直方向缩小0.8倍
    CGAffineTransform transform = CGAffineTransformMakeScale(0.5, 0.8);
    self.label.layer.affineTransform = transform;
}

- (void)test2
{
    //水平方向上平移20;竖直方向平移10
    CGAffineTransform transform = CGAffineTransformMakeTranslation(20, 10);
    self.label.layer.affineTransform = transform;
}

图中蓝色视图是红色视图的父视图,作为初始状态和形变后的样子做对比。第一张是选择,第二种是缩放,第三张是平移。


混合变换
如果想让一个view既缩放又旋转,就用到混合变换了。Core Graphics也给我们提供了方便好用的接口。

/*
 CGAffineTransformIdentity: //单位矩阵

 “CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
 CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
 CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)”
 //两个变换的基础上生成另一个变换
 “CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);”
 */

@property(nonatomic) CGAffineTransform transform; // default is CGAffineTransformIdentity. animatable
//UIView的transform的属性的默认值就是CGAffineTransformIdentity。
调用这些函数要传入一个初始值,即CGAffineTransformIdentity,这个是CGAffineTransform类型的空值。也是UIView的transform属性的默认值。以上几个函数,可以将不同的效果叠加。

- (void)mixTest0
{
    CGAffineTransform transfrom = CGAffineTransformIdentity;
    transfrom = CGAffineTransformRotate(transfrom,DEGREES_TO_RADIANS(60));//旋转60度
    transfrom = CGAffineTransformScale(transfrom, 0.5, 0.6);
    transfrom = CGAffineTransformTranslate(transfrom, 0, 50);
//没有垂直向下移动50,因为会叠加上两个形变的结果,相当于向斜下方移动了50 * 0.6
    self.label.layer.affineTransform = transfrom;
    //“后边的形变会作用在之前形变的结果之上,也就是说旋转之后的平移和平移之后的旋转结果可能不同。
}

  • 3D变换
    上边说的仿射变换和混合变换都是在平面上的效果,图层layer的transform属性(CATransform3D类型 )可以让图层在3D空间内移动或者旋转。CATransform3D是在3维空间内做变换的4 * 4的矩阵。
//3D的变换比仿射变换多了一个角度和一个z轴的参数。
//CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
//CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz) 
//CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)”

下图是3D空间内,针对x,y,z轴以及其旋转方向。


- (void)test3D_x
{
//在竖直方向压缩了 实际是沿着竖直方向倾斜了45度去看  如果是90度则完全看不到
    CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 1, 0, 0);
    self.label.layer.transform = transform;
}

- (void)test3D_y
{
//效果是在水平方向压缩了  实际是沿着水平方向倾斜了45度去看 如果是90度则完全看不到
    CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
    self.label.layer.transform = transform;
}
- (void)test3D_z//效果是在正对着用户的方向上旋转了45度
{
    CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
    self.label.layer.transform = transform;
}


其实单直接对以上函数的参数做变动,看不出太多效果,和自己想象中的3D效果不一样。看着好像是图层进行了压缩,其实是因为相当于我们换个角度去看图层导致。
要想达到透视效果,我们需要对CATransform3D这个矩阵做操作。


  • 透视
    我们不需要去管矩阵计算怎么复杂,我们只要控制一个矩阵中m34的值就可以。m34用于按比例缩放X和Y的值来计算到底要离视角有多远。所以我们可以用CATransform3Dm34的值用来做透视。
    m34的值默认是0,可以通过设置m34-1.0 / d来实现透视效果,d的取值范围500~1000
- (void)testPerspective_x
{
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = - 1.0 / 500;
    transform = CATransform3DRotate(transform, M_PI_4, 1, 0, 0);
    self.label.layer.transform = transform;
}

- (void)testPerspective_y
{
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = - 1.0 / 500;
    transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
    self.label.layer.transform = transform;
}

- (void)testPerspective_z
{
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = - 1.0 / 500;
    transform = CATransform3DRotate(transform, M_PI_4, 0, 0, 1);
    self.label.layer.transform = transform;
}


结果如上图,我们设置了m34的值后,看着才有了3D的效果。具体你效果需要什么样,可以根据自己的需要进行设置。
总结:
变换这块自己平常不怎么用到,偶尔需要用到的时候也总想不起来,在这里总结一下,以后便于查找学习。希望对看到的读者也有所帮助。感谢下边书籍的翻译者,感谢。配套Demo可供参考。
参考书籍:ios核心动画高级技巧

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354