文件夹:
-
The Layer Beneath
2. -
The Layer Tree(图层树)
- The Backing Image(寄宿层)
- Layer Geometry(图层几何学)
- Visual Effects(视觉效果)
- Transforms(变换)
- Specialized Layers(专有图层)
-
Setting Things in Motion
4. -
Implicit Animations(隐式动画)
- Explicit Animations(显式动画)
- Layer Time(图层时间)
- Easing(缓冲)
- Timer-Based Animation(基于定时器的动画)
-
The Performance of a Lifetime
6. -
Tuning for Speed(性能调优)
- Efficient Drawing(高效画图)
- Image IO(图像IO)
- Layer Performance(图层性能)
Core Animation 之 CALayer
The Layer Tree(图层树)
1、图层与视图的差别:
- 视图是以树的数据结构来管理层级关系的。而图层相同也是以树的数据结构来管理层级关系
- 视图在程序中以UIView及其子类来表示。而图层以CALayer及其子类专用 图层来表示
- UIView总是与CALayer是一一相应的关系,所以本质上,iOS上界面上的内容的呈现与动态实际上是通过CALayer来实现的,而UIView是封装了CALayer的基础上加入了事件响应、布局等高级功能。
2、关于视图层级、图层树、呈现树、渲染树
- 视图层级:主要负责实现事件响应、布局等功能,由于视图封装图层。图层向视图暴露部分编程接口与属性,于是通过改动视图的效果能够间接改动图层的属性。
- 图层树:负责定义界面图形的绘制、动画效果,iOS是有一个绘制周期的——60FPS,也就是说图层树负责保存这个周期内的相关属性的改动,而到了周期结束要进行绘制的时候,才把图层树的数据模型更新到呈现树中。
- 呈现树:确定当前屏幕上界面图形的详细效果。用于保存当前屏幕的图形的显示属性,每隔一个绘制周期和图层树同步一次。
- 渲染树:iOS系统会专门创建一个进程来运行图形渲染的任务,当随意APP(包含系统App)须要图形渲染的时间,它们就会把渲染任务发送到该线程去运行渲染。
所以以上四层。每一层都负责不同的任务,其数据流是视图-》图层-》呈现树-》渲染树。
而且绘制周期60FPS也是会随着系统的状态而变化的,若系统资源超载,而会通过降低绘制次数来确保系统能稳定执行。
3、视图动画
视图动画是显式,由于UIView默认把CALayer的隐式动画禁止掉了。所以要通过动画Block的形式才干取消动画的限制。(动画block实际上就是曾经的动画栈)。
而且视图能实现的动画仅仅是图层所开放的一部分,都是2D动画,所以视图动画的效果会稍稍简单。
4、图层动画
图层动画是隐性动画。仅仅要改动图层的属性。其变化都会以默认的渐变形式呈现出来(详细原理见《隐式动画》)。而且图层动画支持很多其它视图动画无法实现的效果。如:
- 阴影、圆角、带颜色的边框
- 3D变化
- 非矩形范围
- 透明遮罩
- 多级非线性动画。
5、更适宜使用CAlayer呈现内容的场景
由于UIView与CALayer都能够呈现内容。尽管CALayer不能直接实现事件响应。但开发人员也能够通过hit-test机制的原理来自己实现事件响应,那什么场景更加适合用CALayer而不是UIView呢?例如以下所看到的:
- 开发同一时候能够在MAC、iOS上执行的跨平台应用
- 使用多种CALayer的子类(专有图层),而且不想创建额外的UIView去封装
- 做一些对性能特别挑剔的工作,如对UIView一些可忽略不计的操作都会引起显著的不同(也能够通过OpenGL来解决)。
The Backing Image(寄宿层)
1、寄宿层&Contents属性
CALayer有一个名曰Contents的属性,这个属性是与寄宿层相相应了,而contents属性指向的对象必须为CGImageRef类型(一个指向CGImage结构的指针),所以寄宿层是用来展示图片所用的。例如以下情况会调用寄宿层:
- 显示图片
- core Graphics
core Graphics能够实现自己定义绘制,但通常不建议那么做,由于core Graphics绘制会默认生成一个绘制专用的存储空间,而这空间有十多M那么多。会占用大量内存,所以Apple不建议实现空的core Graphics更不建议在core Graphics实现不属于该方法的代码。
2、contentGravity属性
与UIView的contentMode属性相相应,用于调整图片的布局,支持一下常量值:
- kCAGravityCenter
- kCAGravityTop
- kCAGravityBottom
- kCAGravityLeft
- kCAGravityRight
- kCAGravityTopLeft
- kCAGravityTopRight
- kCAGravityBottomLeft
- kCAGravityBottomRight
- kCAGravityResize
- kCAGravityResizeAspect
- kCAGravityResizeAspectFill
3、contentsScale
contentsScale属性定义了寄宿层的像素尺寸和视图大小比例,默认是1.0(一个点一个像素),在retina屏幕得设置在2.0(一个点两个像素)。在plus设备上得设备为3.0(一个点3个像素)。
但若contentGravity设置了如kCAGravityResizeAspectFill自己主动适配大小的属性后,contentsScale会不起作用。所以不能依靠contentsScale来做缩放的操作,缩放还是得交给transform或者affineTransform。
3、maskToBounds
该属性与UIView的clipsToBounds属性相相应。都是应用于将超出图层边界的子图层的内容进行裁剪。
这里须要一点须要注意的,但我们实现radiusCorner时,实际上就是通过设置背景颜色来实现的。而与maskToBounds结合才是真正把边角内容裁剪掉,但radiusCorner+maskToBounds结合使用会引发离屏渲染。所以在radiusCorner满足要求。就不要再调用maskToBounds。
4、contentsRect
CALayer的contentsRect同意我们在图层边框内显示寄宿图的一个子域,而contentsRect是一个相对值属性,如{0,0。1,1}表示整个寄宿图,这样的坐标系统也叫单位。例如以下简述iOS下的三种坐标系统单位:
- 点:点是虚拟的像素,也叫逻辑像素。在不同的设备上一个点所代表的像素点是不一样的。如普通屏幕一个点就是一个像素,而retina屏幕一个点就是两个像素。
- 像素:实际的物理像素坐标。
- 单位:一种相对的坐标,优点就是应用相对值,方便移植。
contentsRect有一种经典的使用方法——image sprites(图片拼接,经常使用于游戏),这种使用方法就是用来实现一次性载入多张图片的。由于每一张图片的使用前都要经过,载入——》压缩——》呈现,的一个过程当中载入和压缩是十分耗时的,载入消耗IO,压缩算法的复杂会添加CPU的消耗,所以想游戏这种App须要载入解压大量的图片时,能够把全部图片整合成一张图片来载入解压,然后通过contentsRect裁剪出子图,并显示,能够优化载入解压的过程。
5、contentsCenter
contentsCenter的名字事实上有一点的误导性,事实上际上与UIView的Stretching属性相相应。用来实现寄宿层的缩放时的呈现效果。也是一个相对值单位。
6、customs drwaing
除了通过CGImage设置到contents的方式来实现寄宿层。还能够通过Core Graphics来直接绘制寄宿层,但这样的方式十分消耗内存不建议使用。
CALayer有一个可选的Delegate属性。实现了CALayerDelegate,但CALayer须要又一次绘制,则调用它的displayLayer方法(与UIView的setNeedDispaly相相应),就会调用其代理方法drawLayer:inContext(与UIView的drawRect相相应)。
若在视图层中,仅仅要用户实现了drawRect那么仅仅要屏幕须要又一次绘制那么该方法都会被默认调用。
Layer Geometry(图层几何学)
1、布局
UIView的三个重要布局属性:frame、bounds、center
CALayer的三个重要的布局属性:frame、bounds、position
能够看出UIView与CALayer的布局属性是一一相应的,而唯一有啥区别的就是锚点的命名,UIView为center,而CALayer为position,但锚点最開始都是默觉得图形的中心。
当中frame实际上就是一个虚拟属性,其由bounds与center/position计算所得。所以改动bounds与center/position也会影响到frame的数值。
还有不管是视图还是图层。在屏幕上不管怎么变形,本质上其还是一个矩形。但在旋转的情况下。frame的数值是会事实变动的,例如以下图:
2、锚点
锚点属性是用来指定图层相对于父图层的位置。也能够理解为利用图层的句柄。默觉得图层的中心但也能够改动。在图层中改动了锚点会产生移动(隐性动画),相同的锚点也是一个相对值。
例如以下。为锚点的实验效果图:
图一:时分秒针直接以图层的中点为锚点,由于旋转时也以其为中心,效果例如以下:
图二:将锚点改动成指针的尾端
图三:改动锚点后的旋转效果。
3、坐标系
由于每一个图层都有自己的坐标系,所以CALayer也提供了一系列的方法用于一个点在不同的坐标系之间转换,这些方法特别适合于子图层与父图层之间的坐标转换。
事实上UIView与CALayer都有zPosition。但因为UIView只支持2D变换,所以UIView的zPosition只适合于用来作图层的调整,但更加建议用UIView提供的视图数组管理方法来调整视图的绘制顺序来调整。而CALayer的zPosition是一个重要的三维坐标系。
4、Hit Testing
Hit Testing是iOS中一个十分重要的机制,用于检索点击了的目标图标,与响应链条相互搭配的话。就会将终于目标图标设置为第一响应者。Hit Testing提供了两个核心的方法:
- containPoint:(用于直接推断某个点是否属于某个图层)
- -hitTest(通过递归遍历子对象的方式来直接返回目标图层)
5、自己主动布局
对于UIView。通过UIView暴露出来的UIViewAutoresizingMask和NSLayoutConstraint来实现自己主动布局。
但对于CALayer,则须要手动来操作实现,当中最为简单的方法就是实现CALayerDelegate的例如以下函数:
- (void)layoutSublayersOfLayer:(CALayer *)layer;
在该方法内依据当前layer的属性来计算调整来实现自己主动布局。
由于CALayer实现自己主动布局不方便,所以这也是为什么更加建议使用UIView来实现界面的构建。
Visual Effects(视觉效果)——本节探讨可以通过CALayer实现的附加视觉效果
1、圆角
CALayer有一个叫做cornerRadius的属性控制图层角的曲率,这个曲率仅仅影响背景颜色而不影响图片或者子图片。圆角的计算原理就是一个以CALayer的中点,曲率所设的半径的原与矩形的交集就是目标图形。
另一个名曰maskToBounds属性,就是实现将图层里面边界外的图形所有分割丢弃。
所以通过cornerRadius+maskToBounds组合能够实现圆角,但同一时候会引发离屏渲染,若是小量的离屏渲染还好,但如滚动栏的场景,开会有大量的离屏渲染的任务产生,就会严重影响性能,这一点也是注意优化的。详细效果例如以下图所看到的:
2、图层边框
通过设置CALayer的borderWidth与borderColor两个属性能够改动边框的效果。
效果例如以下:
3、阴影
阴影是一种能达到图层深度暗示效果的装饰。
CALayer提供下面參数来定制阴影的效果:
- shadowOpacity:设置一个大于零的数值,那么阴影就会显示在图层以下(默觉得0)。
- shadowColor:设置阴影的颜色(默认黑色)
- shadowOffset:设置阴影的偏移量(默认{0。-3})
- shadowRadius:设置阴影模糊度,数值越大。阴影的模糊度越高(默觉得0)。曲率越大,阴影效果越明显。
shadowRadius的设置效果图例如以下:
有一点须要注意的,就是阴影的绘制是属于离屏绘制。是比較效果资源的。所以一定要降低同一屏幕进行大量阴影绘制的情况。
4、阴影裁剪
图层的阴影很多其它是继承于内容的外形,而不是依据边界和角半径来确定。为了计算出阴影的形状。core animation会将寄宿层也考虑在内。
但若直接maskToBounds来裁剪,会把阴影效果也裁减掉。
为了解决以上问题。能够通过专门引入一个阴影图层来解决,详细效果例如以下:
图一:直接maskToBounds裁剪会把阴影效果一并裁剪掉。
图二:通过加入一个另外的阴影图层在以下,然它来实现阴影。而详细的内容图层就直接maskToBounds裁剪。
图三:终于既能实现裁剪,又能实现阴影。
PS:不管是阴影还是圆角裁剪都会引发离屏渲染,大量的该类型的图形须要渲染的话。会减低帧率。
5、shadowPath 属性
阴影并一定是方形的。我们也能够通过shadowPath来定制自己想要的阴影形状。详细效果例如以下所看到的:
6、图层蒙版
通过masksToBounds属性。我们能够实现边界裁剪,但我们还须要更加灵活的裁剪需求的时候就能够通过图层蒙版来实现。CALayer提供一个mask的属性来解决一个问题。而mask本来就是指向还有一个图层的指针。其详细原理例如以下图所看到的:
从上图效果能够知道mask舒心仅仅关心形状的交集,而颜色还是由原来的图形的颜色决定。
另一点须要注意的是图层蒙版也会引发离屏渲染,会带来性能问题,所以使用的时候也得多加注意。
7、拉伸过滤
当我们视图显示一个图片的时候。都应该以正确的比例,正确的1:1像素显示在屏幕上。原因例如以下:
- 可以显示更好的画质,像素既没有被压缩也没有被拉伸
- 能更好使用内存,由于这就是你要存储的东西
- 最好的性能表现,CPU不须要为此额外的计算
但有时候我们就须要缩略图。所专门另外存储缩略图这对内存来说。
这时就能够通过CALayer的minificationFilter(缩小滤波器)和magnificationFilter(方法滤波器)属性实现图形的缩放算法。当中提供下面三种默认的缩放算法:
- kCAFilterLinear(双线性滤波算法,默认算法)
- kCAFilterTrilinear(三线性滤波算法)
- kCAFilterNearest(近期滤波算法)
对于大图的缩放,採用kCAFilterLinear、kCAFilterTrilinear,效果会比較好。
对于小图、较少斜线的图的缩放,。採用kCAFilterNearest效果比較好。
图一:採用kCAFilterLinear的方法滤波器算法的效果。
图二:採用kCAFilterNearest的放大滤波器算法的效果:
8、透明组
UIView有一个alpha属性类确定视图的透明度。而CALayer有一个与之相应的属性——opacity。这两个属性都会影响到子图层。例如以下图所看到的:
当我们将view2的alpha数值设置为0.5,这时候,对于label所处的点的颜色计算公式为:50%label + 25%view + 25%background,所以就是灰色偏白的颜色。
若想整个图层的色调保持一致,能够通过将shouldRasterize属性设置为YES,那么图层及其子图层将被整合成一个总体的图片。效果例如以下:
图一:shouldRasterize属性设置为默认值NO的效果。
图二:shouldRasterize属性设置为默认值YES的效果。
Transforms(变换)
1、仿射变换
UIView相应的transfrom属性是一个CGAffineTransfrom类型。用于实现二维空间旋转、平移、缩放、斜切。
而CALayer的transform属性是一个CATransforms3D。能应用3维空间进行旋转、平移、缩放、斜切等效果。
当中,仿射变化的数学原理例如以下:
只是iOS为了运算的方便。已经提供了三个标准方法分别用于实现旋转、缩放。平移,而斜切得靠原生运算来实现。
当中有一点须要注意的,就是旋转的angle是以弧度制为单位的。
iOS系统提供下面方法来实现混合变换,能同一下面的组合函数实现复杂的变形模式:
图一:创建一个空的变换结构体。
图二:不断叠加变换结构体
图三:直接将两个变换结构体合并
剪切变换的效果与事实上现代码:
2、3D变化
3D变化与2D变化是十分相似的,不同的仅仅是3D变换是3个维度的,加入了Z轴。其数学原理例如以下:
这样的矩阵运算还是挺麻烦的。所以iOS系统提供给我们便捷的方法:
相同也会有变换叠加的方法,当中旋转的时候一定要注意当前的旋转的參考轴,顺时针旋转为正值,逆时针旋转为负值。
3、透视投影
在真实的世界中,当物体远离我们。因为视角的原因,其会变小。所以为了让3D效果更佳真实,须要引入投影变换,尽管core animation并没有提供给我们,但十分简单,其数学实现例如以下:
仅仅要将m34 = -1/d, d= 500~1000,(d越小越失真,d越大透视效果越弱)。
图3.1:没实现透视投影的旋转效果。
图3.2:实现了透视投影的旋转效果。
4、灭点
在人的视觉中。当物体离人越远则会变得越小,当接近无穷远的时候就会汇聚成一个不可见的点,这个点就叫灭点。现实生活中,这个点通常就是中心点,所以在程序中我们也要让图形的灭点集中在屏幕的中点,例如以下所看到的:
而实现方式则是。首先加入图形的时候先以屏幕中点为锚点加入,然后通过transfrom来讲图层移动到恰当的位置。
5、sublayerTransform
sublayerTransform是一种将全部对应的配置统一设置到该图层的全部子图层的便捷属性。
6、3D坐标下的图层背面
在3D坐标下,图层的背面也是会绘制的,并且是正面的镜像。
我们能够通过CALayer的doubleSided属性来决定是否运行双面绘制。
7、扁平化图层
假设父图层的坐标发生变换,那么子图层也会随着父图层而进行相同的变换,如7.1图所看到的。但有时我们仅仅想变换父图层并不想变换子图层。这时就得做相对变换来抵消掉父图层的变换。让视觉效果看起来子图层是精巧的。例如以下图所看到的:
图7.1:2D相对旋转理论图
图7.2:2D相对旋转效果图
图7.3:3D相对旋转理论图
图7.4:3D相对旋转实际效果图
我们能够看出,在2D坐标系下。相对变换是合理的。但在3D坐标系下,相对变换的结果并不如预想的一样,为什么呢?
这是由于core Animation图层尽管存在于3D空间之内,但并非每个图层都存在于同一个3D空间之间。
而用户是以当前window所在的3D坐标系为參考的,这时7.4图的3D坐标系与window的已经不重合的,所以在我们的视觉里面,就是看不到预想的效果,这就是图层扁平化。
图层扁平化让core animation创建复杂的3D场景变得十分困难,由于非常难使用图层树去创建一个3D结构的层级关系——将全部的场景下的3D都保持同样的3D坐标系。
只是CALayer提供一个专用图层——CATransformLayer来解决问题,全部加入到该图层内的3D图形都共享一个标准坐标系。
8、3D场景下的光亮和阴影
略。临时不懂。
9、3D场景下的点击事件
在处理点击事件,一定要注意点击响应是由UIView中的图层结构来决定的,而不是CALayer在屏幕上的呈现效果,所以得注意事件拦截的顺序。
能够通过设置userInteractionEnabled以及简单的视图覆盖来实现点击事件正确的传递。
Specialized Layers(专有图层)
1、CAShapeLayer
2、CATextLayer
3、CATransformLayer
4、CAGradientLayer
5、CAReplicatorLayer
6、CAScrollLayer
7、CATiledLayer
8、CAEmitterLayer
9、CAEAGLlayer
10、AVPlayerLayer
Core Animation 之 动画
Original: https://www.cnblogs.com/cynchanpin/p/8257899.html
Author: cynchanpin
Title: Core Animation学习总结
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/551489/
转载文章受原作者版权保护。转载请注明原作者出处!