CoreAnimation 变换
CoreAnimation 变换
博客园MakeDown支持不佳,如有需要请进GitHub
本片博客主要内容:
- 仿射变换 - CGAffineTransform
- 3D变换 - CATransform3D
仿射变换 - CGAffineTransform
CGAffineTransform
是用于二维空间的旋转,缩放和平移的属性.首先展示一个简单的样例,将图片顺时针旋转45°⬇️.
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformRotate(transform, M_PI_4);
self.imageView.layer.affineTransform = transform;
向右平移200⬇️.
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformTranslate(transform, 200, 0);
self.imageView.layer.affineTransform = transform;
先进行旋转后进行向右平移⬇️.
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformRotate(transform, M_PI_4);
transform = CGAffineTransformTranslate(transform, 200, 0);
self.imageView.layer.affineTransform = transform;
注意:
图片二与图片三同是向右平移200,但是通过观察两图的对比不难发现,图片三的平移距离明显比图片二的距离小,与此同时图片三相对图片二向下也有一定的平移,这是因为transform
的上一次设置会对下一次设置的效果产生影响.
混合变换方法 CGAffineTransformConcat
⬇️.
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformRotate(transform, M_PI_4);
CGAffineTransform transformTwo = CGAffineTransformMakeTranslation(-200, 0);
transform = CGAffineTransformConcat(transform, transformTwo);
self.imageView.layer.affineTransform = transform;
3D变换 - CATransform3D
CATransform3D
支持图层在三维空间内的操作,x轴旋转⬇️.
CATransform3D transform3d = CATransform3DIdentity;
transform3d = CATransform3DRotate(transform3d, M_PI_4, 1, 0, 0);
self.imageView.layer.transform = transform3d;
y轴旋转⬇️.
CATransform3D transform3d = CATransform3DIdentity;
transform3d = CATransform3DRotate(transform3d, M_PI_4, 0, 1, 0);
self.imageView.layer.transform = transform3d;
z轴旋转⬇️.
CATransform3D transform3d = CATransform3DIdentity;
transform3d = CATransform3DRotate(transform3d, M_PI_4, 0, 0, 1);
self.imageView.layer.transform = transform3d;
以上三张样图只能让我们发现与原有图片有所不同,但是不能明显的区别出差别在哪里,此时我们可以设置m34
来实现透视投影的效果.
透视投影 - x轴旋转⬇️.
CATransform3D transform3d = CATransform3DIdentity;
transform3d.m34 = - 1.0 / 500.0;
transform3d = CATransform3DRotate(transform3d, M_PI_4, 1, 0, 0);
self.imageView.layer.transform = transform3d;
透视投影 - y轴旋转⬇️.
CATransform3D transform3d = CATransform3DIdentity;
transform3d.m34 = - 1.0 / 500.0;
transform3d = CATransform3DRotate(transform3d, M_PI_4, 0, 1, 0);
self.imageView.layer.transform = transform3d;
透视投影 - z轴旋转⬇️.
CATransform3D transform3d = CATransform3DIdentity;
transform3d.m34 = - 1.0 / 500.0;
transform3d = CATransform3DRotate(transform3d, M_PI_4, 0, 0, 1);
self.imageView.layer.transform = transform3d;
灭点
: 当在透视角度绘图的时候,远离相机视角的物体将会变小变远,当远离到一个极限距离,它们就缩成了一个点,因此所有的物体最后都汇聚消失在同一个点.在现实中,这个点通常是视图的中心,于是为了在应用中创建拟真效果的透视,这个点应该聚在屏幕中点,或者至少是包含所有3D对象的视图中点.
了解灭点
后便会遇到一个问题,通常状态下手机屏幕所显示的内容存在着很多图层,那么我们要一一设置他们的灭点吗?显然这种方法是不可行的以为它十分不方便.封装?或许是一个错的方法,但是那样会带来一个严重的后果就是不灵活,那么应该怎样去做?sublayerTransform
是最完美的选择,它也是CATransform3D类型,但和对一个图层的变换不同,它影响到所有的子图层.这意味着你可以一次性对包含这些图层的容器做变换,于是所有的子图层都自动继承了这个变换方法.
做一个简单的测试.
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = - 1.0 / 500;
self.view.layer.sublayerTransform = perspective;
CATransform3D transform = CATransform3DIdentity;
CATransform3D twoTransform = CATransform3DIdentity;
transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
twoTransform = CATransform3DRotate(twoTransform, -M_PI_4, 0, 1, 0);
self.imageView.layer.transform = transform;
self.imageTwoView.layer.transform = twoTransform;
背面
: 设置图层翻转180°.
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = - 1.0 / 500;
self.view.layer.sublayerTransform = perspective;
CATransform3D transform = CATransform3DIdentity;
CATransform3D twoTransform = CATransform3DIdentity;
transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
twoTransform = CATransform3DRotate(twoTransform, -M_PI, 0, 1, 0);
self.imageView.layer.transform = transform;
self.imageTwoView.layer.transform = twoTransform;
背面的绘制是很浪费cpu以及gpu的,因此我们更多的时候是需要禁止绘制图层背面的.
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = - 1.0 / 500;
self.view.layer.sublayerTransform = perspective;
CATransform3D transform = CATransform3DIdentity;
CATransform3D twoTransform = CATransform3DIdentity;
transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
twoTransform = CATransform3DRotate(twoTransform, -M_PI, 0, 1, 0);
self.imageView.layer.transform = transform;
self.imageTwoView.layer.transform = twoTransform;
self.imageTwoView.layer.doubleSided = NO;// 不绘制背面
最后来讨论一下,子图的相对父图层的逆变换是否会恢复原状.z轴?
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = - 1.0 / 500;
self.view.layer.sublayerTransform = perspective;
CATransform3D outer = CATransform3DIdentity;
CATransform3D inter = CATransform3DIdentity;
outer = CATransform3DRotate(outer, M_PI_4, 0, 0, 1);
inter = CATransform3DRotate(inter, -M_PI_4, 0, 0, 1);
self.outer.layer.transform = outer;
self.inter.layer.transform = inter;
z轴状态下是可以恢复原状的.y轴?
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = - 1.0 / 500;
self.view.layer.sublayerTransform = perspective;
CATransform3D outer = CATransform3DIdentity;
CATransform3D inter = CATransform3DIdentity;
outer = CATransform3DRotate(outer, M_PI_4, 0, 1, 0);
inter = CATransform3DRotate(inter, -M_PI_4, 0, 1, 0);
self.outer.layer.transform = outer;
self.inter.layer.transform = inter;
y轴并不是,这是由于尽管Core Animation图层存在于3D空间之内,但它们并不都存在同一个3D空间.每个图层的3D场景其实是扁平化的,当你从正面观察一个图层,看到的实际上由子图层创建的想象出来的3D场景,但当你倾斜这个图层,你会发现实际上这个3D场景仅仅是被绘制在图层的表面.