概述
CATransform3D是一个用于处理3D形变的类,其可以改变控件的平移、缩放、旋转、斜交等,其坐标系统采用的是三维坐标系,即向右为x轴正方向,向下为y轴正方向,垂直屏幕向外为z轴正方向
在CALayer中有一个transform属性便是专门用来控制3D形变的,其使用方法如下
样例素材
在介绍CALayer形变的过程中,我们会使用一个UIImageView图片为例,对各动画效果进行演示
<code class="language-objc hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@property</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">nonatomic</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">strong</span>) <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIImageView</span> *demoImageView; - (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)viewDidLoad { [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span> viewDidLoad]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.demoImageView</span> = [[<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIImageView</span> alloc] initWithFrame:CGRectMake(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>, [[UIScreen mainScreen] bounds]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.width</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">40</span>, [[UIScreen mainScreen] bounds]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.height</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">40</span>)]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.demoImageView</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.image</span> = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIImage</span> imageNamed:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"demo"</span>]; [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.view</span> addSubview:<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.demoImageView</span>]; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
方法介绍
- CATransform3DMakeTranslation实现以初始位置为基准,在x轴方向上平移x单位,在y轴方向上平移y单位,在z轴方向上平移z单位
<code class="language-objc hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 格式</span> CATransform3DMakeTranslation (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> tx, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> ty, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> tz) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 样例</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.demoImageView</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.layer</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.transform</span> = CATransform3DMakeTranslation(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
注: 注: 当tx为正值时,会向x轴正方向平移,反之,则向x轴负方向平移;当ty为正值时,会向y轴正方向平移,反之,则向y轴负方向平移;当tz为正值时,会向z轴正方向平移,反之,则向z轴负方向平移
- CATransform3DMakeScale实现以初始位置为基准,在x轴方向上缩放x倍,在y轴方向上缩放y倍,在z轴方向上缩放z倍
<code class="language-objc hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 格式</span> CATransform3DMakeScale (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> sx, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> sy, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> sz) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 样例</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.demoImageView</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.layer</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.transform</span> = CATransform3DMakeScale(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
注: 当sx为正值时,会在x轴方向上缩放x倍,反之,则在缩放的基础上沿着竖直线翻转;当sy为正值时,会在y轴方向上缩放y倍,反之,则在缩放的基础上沿着水平线翻转
- CATransform3DMakeRotation实现以初始位置为基准,在x轴,y轴,z轴方向上
逆
时针旋转angle弧度(弧度=π/180×角度,M_PI弧度代表180角度),x,y,z三个参数只分是否为0
<code class="language-objc hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 格式</span> CATransform3DMakeRotation (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> angle, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> x, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> y, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> z) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 样例</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.demoImageView</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.layer</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.transform</span> = CATransform3DMakeRotation(M_PI*<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.25</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
注: 当x,y,z值为0时,代表在该轴方向上不进行旋转,当值为1时,代表在该轴方向上进行
逆
时针旋转,当值为-1时,代表在该轴方向上进行顺
时针旋转
- CATransform3DTranslate实现以一个已经存在的形变为基准,在x轴方向上平移x单位,在y轴方向上平移y单位,在z轴方向上平移z单位
<code class="language-objc hljs rsl has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 格式</span> CATransform3DTranslate (CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 样例</span> CATransform3D <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">transform</span> = CATransform3DIdentity; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">transform</span>.m34 = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span>/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">500</span>; self.demoImageView.layer.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">transform</span> = CATransform3DTranslate(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">transform</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
- CATransform3DScale实现以一个已经存在的形变为基准,在x轴方向上缩放x倍,在y轴方向上缩放y倍,在z轴方向上缩放z倍
<code class="language-objc hljs rsl has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 格式</span> CATransform3DScale (CATransform3D t, CGFloat sx, CGFloat sy, CGFloat sz) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 样例</span> CATransform3D <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">transform</span> = CATransform3DIdentity; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">transform</span>.m34 = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span>/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">500</span>; self.demoImageView.layer.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">transform</span> = CATransform3DScale(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">transform</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
- CATransform3DRotate实现以一个已经存在的形变为基准,在x轴,y轴,z轴方向上
逆
时针旋转angle弧度(弧度=π/180×角度,M_PI弧度代表180角度),x,y,z三个参数只分是否为0
<code class="language-objc hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 格式</span> CATransform3DRotate (CATransform3D t, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> angle, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> x, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> y, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> z) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 样例</span> CATransform3D transform = CATransform3DIdentity; transform<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.m34</span> = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span>/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">500</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.demoImageView</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.layer</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.transform</span> = CATransform3DRotate(transform, M_PI*<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.25</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
- 特殊地,transform属性默认值为CATransform3DIdentity,可以在形变之后设置该值以还原到最初状态
<code class="language-objc hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">// 样例 self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.demoImageView</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layer</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.transform</span> = CATransform3DIdentity<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
关于结构体中的m34
在默认情况下,系统采用正交投影,对于3D形变实际上是看不到3D效果的,在CATransform3D结构体中有一个m34便允许我们将正交投影修改为有近大远小立体效果的透视投影,其中m34 = -1.0/z,这个z为观察者与控件之间的距离
注: m34必须在赋值transform之前设置才会生效