《iOS 三问》 -- CALayer 常用几何变换 transform
和 UIView 一样,CALayer 也可以设置 Transform(那当然,因为 uiview 的绘图就是靠 layer 来实现的),而且 layer 的 transform 比 view 来说要强大太多了。
1 仿射变换
在介绍 UIView 的几何变形时,我们提到了通过赋值 view 的 transform
属性,可以设置 view 的几何变换。我们之所以称之为 “几何” 变形,就是因为对图象的变型操作实际上是利用了几何的知识。
比如我们常用的,CGAffineTransform
中的 affine
,就是 仿射变换
,用于在二维空间对图象进行几何变换(缩放、平移、旋转等)。他是利用将图象和一个变换矩阵相乘以得出的结果矩阵来实现变换的。
在应用的时候,我们无需理解其中复杂的几何计算,因为 CALayer 提供了简单的 api 供我们使用,我们只需要改变 layer 的affineTransform属性。
1 | ・CGAffineTransformIdentity :【常量】什么都不做的变换(初始变换) |
下面有一个输出一个指南针图层的实例,利用变形知识画一个指南针:
实现效果可以在我的 iOSOneDemo 中对应这篇文章的章节查看。
1 |
|
2 3D 变换
CG 的前缀告诉我们, CGAffineTransform
类型属于 Core Graphics
框架,Core Graphics
实际上是一个严格意义上的 2D 绘图 API,并且 CGAffineTransform
仅仅对 2D 变换有效。
CATransform3D
可以对图层在 3D 空间内进行移动或转动。和 CGAffineTransform
类似, CATransform3D
也是一个矩阵,但是和 3x3 的矩阵不同, CATransform3D
是一个可以在 3 维空间内做变换的 4x4 的矩阵
2.1 3D 变换主要方法
1 |
|
oneDemo 中 3D 变换的示例
1 | //slider.value 为 0-100 |
2.2 背面绘制
CALayer 有一个叫做doubleSided的属性来控制图层的背面是否要被绘制。是 BOOL 类型,默认为 YES ,如果设置为 NO ,那么当图层正面从相机视角消失的时候,它将不会被绘制。
2.3 透视投影
在真实世界中,当物体远离我们的时候,由于视角的原因看起来会变小,理论上说远离我们的视图的边要比靠近视角的边跟短,但实际上,如果你什么都不设置,这样的情况并没有发生。
- m34
CATransform3D 的透视效果通过一个矩阵中一个很简单的元素来控制 – m34, 可以按比例缩放 X 和 Y 的值来计算到底要离视角多远。
1 |
|
2.4 灭点
当在透视角度绘图的时候,远离相机视角的物体将会变小变远,当远离到一个极限距离,它们可能就缩成了一个点,于是所有的物体最后都汇聚消失在同一个点。
在现实中,这个点通常是视图的中心,于是为了在应用中创建拟真效果的透视,这个点应该聚在屏幕中点,或者至少是包含所有 3D 对象的视图中点。
Core Animation 定义了这个点位于变换图层的 anchorPoint
. 这就是说,当图层发生变换时,这个点永远位于图层变换之前 anchorPoint
的位置。
当改变一个图层的 position
,你也改变了它的灭点,做 3D 变换的时候要时刻记住这一点,当你视图通过调整 m34
来让它更加有 3D 效果,应该首先把它放置于屏幕中央,然后通过平移来把它移动到指定位置(而不是直接改变它的 position
),这样所有的 3D 图层都共享一个灭点。
3 sublayerTransform 属性
如果有多个视图或者图层,每个都做 3D 变换,那就需要分别设置相同的 m34
值,并且确保在变换之前都在屏幕中央共享同一个 position
。使用 CALayer 的 sublayerTransform
属性会让父层的改变影响到所有的子图层,这意味着你可以一次性对包含这些图层的容器做变换,也就是所有子图层都自动继承了父图层的变换方法。
比如,我们
1 | CATransform3D perspective = CATransform3DIdentity; |
4 示例 - 做一个立方体骰子
实现效果可以在我的 iOSOneDemo 中对应这篇文章的章节查看。
1 |
|
5 引用
【1】[Matt Neuburg - 《Programming iOS deep into views,view controllers and frameworks》]
【2】[Nick LockWood - 《iOS Core Animation: Advanced Techniques》]