Core Animation学习笔记(一)
用了几天时间学习了Core Animation相关知识,今晚就在此做个简单的总结吧!
1.简单的介绍下图层和视图的区别
在iOS当中,所有的视图都从一个叫做UIVIew的基类派生而来,UIView可以处理触摸事件,可以支持基于Core Graphics绘图,可以做仿射变换(例如旋转或者缩放),或者简单的类似于滑动或者渐变的动画。和UIView最大的不同是CALayer不处理用户的交互。CALayer并不清楚具体的响应链(iOS通过视图层级关系用来传送触摸事件的机制),于是它并不能够响应事件,即使它提供了一些方法来判断是否一个触点在图层的范围之内。
每一个UIView都有一个CALayer实例的图层属性,也就是所谓的backing layer,视图的职责就是创建并管理这个图层,以确保当子视图在层级关系中添加或者被移除的时候,他们关联的图层也同样对应在层级关系树当中有相同的操作。实际上这些背后关联的图层才是真正用来在屏幕上显示和做动画,UIView仅仅是对它的一个封装,提供了一些iOS类似于处理触摸的具体功能,以及Core Animation底层方法的高级接口。
这里有一些UIView没有暴露出来的CALayer的功能:
(1)阴影,圆角,带颜色的边框
(2)3D变换
(3)非矩形范围
(4)透明遮罩
(5)多级非线性动画
2.坐标系统
在CALayer中的坐标系和UIView中相同,都是左上角为(0,0),右下角为(1,1)。需要注意的时CALayer的锚点(anchorPoint)默认坐标是(0.5,0.5),而CALayer的position属性指的就是这个图层的锚点(anchorPoint)在它的父图层中的位置。这样说更通俗点,新手容易理解。ios使用了以下坐标系统:
•点 —— 在iOS和Mac OS中最常见的坐标体系。点就像是虚拟的像素,也被称作逻辑像素。在标准设备上,一个点就是一个像素,但是在Retina设备上,一个点等于2*2个像素。iOS用点作为屏幕的坐标测算体系就是为了在Retina设备和普通设备上能有一致的视觉效果。
•像素 —— 物理像素坐标并不会用来屏幕布局,但是仍然与图片有相对关系。UIImage是一个屏幕分辨率解决方案,所以指定点来度量大小。但是一些底层的图片表示如CGImage就会使用像素,所以你要清楚在Retina设备和普通设备上,他们表现出来了不同的大小。
•单位 —— 对于与图片大小或是图层边界相关的显示,单位坐标是一个方便的度量方式, 当大小改变的时候,也不需要再次调整。单位坐标在OpenGL这种纹理坐标系统中用得很多,Core Animation中也用到了单位坐标。 默认的contentsRect是{0, 0, 1, 1},这意味着整个图默认都是可见的,如果我们指定一个小一点的矩形,图片就会被裁剪
3.视觉效果
CALayer的视觉效果主要有 圆角,图层的边框,阴影,图层蒙版,缩放过滤,成组透明等等。github有源码演示这些功能的简单使用,https://github.com/tapharmonic/Core-Animation-Demos;
4.变换
(1)仿射变换(CGAffineTransform)
CGAffineTransform是一个可以和二维空间向量做乘法变换运算的3 x 2的矩阵。
Core Graphics提供了一系列函数,让毫无数学基础的开发者能够简单地做一些变换。
创建了一个CGAffineTransform实例可以用如下几个函数:
CGAffineTransformMakeRotation(CGFloat angle) // 旋转一个角度
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy) // 缩放
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty) // 平移,每个点都平移一定距
(2)3D变换(CATransform3D)
CGAffineTransform仅仅对2D变换有效。和CGAffineTransform类似,CATransform3D也是一个矩阵,但是和2x3的矩阵不同,CATransform3D是一个可以在3维空间内做变换的4x4的矩阵。
Core Animation提供了一系列的方法用来创建和组合CATransform3D类型的矩阵:
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)//旋转
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz) //缩放
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)//移动
这里的Z轴垂直于手机屏幕向外为正方向。
举例说明一下:
绕Y轴旋转的图层
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//绕Y轴选装45度
CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
self.layerView.layer.transform = transform;
}
@end
如果把CATransform3DMakeRotation(M_PI_4, 0, 1, 0)的参数改成
CATransform3DMakeRotation(M_PI_4, 1, 0, 0)就变成了绕X轴旋转45度。以此类推CATransform3DMakeRotation(M_PI_4, 0, 0, 1)就表示绕Z轴旋转45度,其实就是和在平面旋转45度的效果一样。如果是CATransform3DMakeRotation(M_PI_4, 1, 1, 0)则表示沿着X轴和Y轴的对角线旋转45度。其他情况以此类推。
(3)再介绍下透视投影
CATransform3D的透视效果通过矩阵中m34的值来控制。m34用于按比例缩放X和Y的值来计算到底要离视角多远。
CATransform3D的矩阵如下图所示:
m34的默认值是0,我们可以通过设置m34为(-1.0 / d)来应用透视效果,d代表了视角相机和屏幕之间的距离,以像素为单位,那应该如何计算这个距离呢?大概估算一个就行了。
因为视角相机实际上并不存在,所以可以根据屏幕上的显示效果自由决定它放置的位置。通常500-1000就已经很好了,但对于特定的图层有时候更小后者更大的值会看起来更舒服,减少距离的值会增强透视效果,所以一个非常微小的值会让它看起来更加失真,然而一个非常大的值会让它基本失去透视效果。
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 创建一个新的transform
CATransform3D transform = CATransform3DIdentity;
// 应用透视
transform.m34 = - 1.0 / 500.0;
// 绕Y轴旋转45度
transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
// 应用到图层上
self.layerView.layer.transform = transform;
}
@end
配上一张效果图:
今天就写这么多吧。