Core Animation学习总结

文件夹:

  1. The Layer Beneath
    2.

  2. The Layer Tree(图层树)

  3. The Backing Image(寄宿层)
  4. Layer Geometry(图层几何学)
  5. Visual Effects(视觉效果)
  6. Transforms(变换)
  7. Specialized Layers(专有图层)
  8. Setting Things in Motion
    4.

  9. Implicit Animations(隐式动画)

  10. Explicit Animations(显式动画)
  11. Layer Time(图层时间)
  12. Easing(缓冲)
  13. Timer-Based Animation(基于定时器的动画)
  14. The Performance of a Lifetime
    6.

  15. Tuning for Speed(性能调优)

  16. Efficient Drawing(高效画图)
  17. Image IO(图像IO)
  18. 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、锚点

锚点属性是用来指定图层相对于父图层的位置。也能够理解为利用图层的句柄。默觉得图层的中心但也能够改动。在图层中改动了锚点会产生移动(隐性动画),相同的锚点也是一个相对值。

例如以下。为锚点的实验效果图:

图一:时分秒针直接以图层的中点为锚点,由于旋转时也以其为中心,效果例如以下:

Core Animation学习总结

图二:将锚点改动成指针的尾端

图三:改动锚点后的旋转效果。

3、坐标系

由于每一个图层都有自己的坐标系,所以CALayer也提供了一系列的方法用于一个点在不同的坐标系之间转换,这些方法特别适合于子图层与父图层之间的坐标转换。

Core Animation学习总结

事实上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的设置效果图例如以下:

Core Animation学习总结

有一点须要注意的,就是阴影的绘制是属于离屏绘制。是比較效果资源的。所以一定要降低同一屏幕进行大量阴影绘制的情况。

4、阴影裁剪

图层的阴影很多其它是继承于内容的外形,而不是依据边界和角半径来确定。为了计算出阴影的形状。core animation会将寄宿层也考虑在内。

但若直接maskToBounds来裁剪,会把阴影效果也裁减掉。

为了解决以上问题。能够通过专门引入一个阴影图层来解决,详细效果例如以下:

图一:直接maskToBounds裁剪会把阴影效果一并裁剪掉。

Core Animation学习总结

图二:通过加入一个另外的阴影图层在以下,然它来实现阴影。而详细的内容图层就直接maskToBounds裁剪。

Core Animation学习总结

图三:终于既能实现裁剪,又能实现阴影。

Core Animation学习总结

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的效果。

Core Animation学习总结

图二:shouldRasterize属性设置为默认值YES的效果。

Transforms(变换)

1、仿射变换

UIView相应的transfrom属性是一个CGAffineTransfrom类型。用于实现二维空间旋转、平移、缩放、斜切。

而CALayer的transform属性是一个CATransforms3D。能应用3维空间进行旋转、平移、缩放、斜切等效果。

当中,仿射变化的数学原理例如以下:

Core Animation学习总结

只是iOS为了运算的方便。已经提供了三个标准方法分别用于实现旋转、缩放。平移,而斜切得靠原生运算来实现。

Core Animation学习总结

当中有一点须要注意的,就是旋转的angle是以弧度制为单位的。

iOS系统提供下面方法来实现混合变换,能同一下面的组合函数实现复杂的变形模式:

图一:创建一个空的变换结构体。

Core Animation学习总结

图二:不断叠加变换结构体

Core Animation学习总结

图三:直接将两个变换结构体合并

剪切变换的效果与事实上现代码:

2、3D变化

3D变化与2D变化是十分相似的,不同的仅仅是3D变换是3个维度的,加入了Z轴。其数学原理例如以下:

Core Animation学习总结

这样的矩阵运算还是挺麻烦的。所以iOS系统提供给我们便捷的方法:

Core Animation学习总结

相同也会有变换叠加的方法,当中旋转的时候一定要注意当前的旋转的參考轴,顺时针旋转为正值,逆时针旋转为负值。

3、透视投影

在真实的世界中,当物体远离我们。因为视角的原因,其会变小。所以为了让3D效果更佳真实,须要引入投影变换,尽管core animation并没有提供给我们,但十分简单,其数学实现例如以下:

Core Animation学习总结

仅仅要将m34 = -1/d, d= 500~1000,(d越小越失真,d越大透视效果越弱)。

图3.1:没实现透视投影的旋转效果。

图3.2:实现了透视投影的旋转效果。

4、灭点

在人的视觉中。当物体离人越远则会变得越小,当接近无穷远的时候就会汇聚成一个不可见的点,这个点就叫灭点。现实生活中,这个点通常就是中心点,所以在程序中我们也要让图形的灭点集中在屏幕的中点,例如以下所看到的:

Core Animation学习总结

而实现方式则是。首先加入图形的时候先以屏幕中点为锚点加入,然后通过transfrom来讲图层移动到恰当的位置。

5、sublayerTransform

sublayerTransform是一种将全部对应的配置统一设置到该图层的全部子图层的便捷属性。

6、3D坐标下的图层背面

在3D坐标下,图层的背面也是会绘制的,并且是正面的镜像。

我们能够通过CALayer的doubleSided属性来决定是否运行双面绘制。

7、扁平化图层

假设父图层的坐标发生变换,那么子图层也会随着父图层而进行相同的变换,如7.1图所看到的。但有时我们仅仅想变换父图层并不想变换子图层。这时就得做相对变换来抵消掉父图层的变换。让视觉效果看起来子图层是精巧的。例如以下图所看到的:

图7.1:2D相对旋转理论图

Core Animation学习总结

图7.2:2D相对旋转效果图

图7.3:3D相对旋转理论图

Core Animation学习总结

图7.4:3D相对旋转实际效果图

Core Animation学习总结

我们能够看出,在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/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 浅谈-动态路由之OSPF的理解

    在网络中,路由相当于就是一张地图,让路由器知道这个对应的IP数据包应该往哪端口、网段走;而这个”地图”我们称之为路由表,不同的目的IP路由表的下一个跳也不同…

    技术杂谈 2023年6月21日
    098
  • 抽象 类乐器 期末代码

    abstract class YueQi{ //表示发出声音的功能 public abstract void sound(); } //子类钢琴 class Piano exten…

    技术杂谈 2023年6月21日
    078
  • 面向对象ooDay9

    同一个对象被造型为不同的类型时,有不同的功能——-所有对象都是多态的(明天总结详细讲) 对象的多态:水、我、你…… 同一类型的引用在…

    技术杂谈 2023年7月11日
    069
  • 上周热点回顾(7.4-7.10)

    热点随笔: · 一大波开源小抄来袭 (削微寒)· 一题多解,ASP.NET Core应用启动初始化的N种方案[上篇] (Artech)· [开源精品] .NET Redis Cli…

    技术杂谈 2023年5月31日
    082
  • Pytest fixture及conftest详解

    前言 fixture是在测试函数运行前后,由pytest执行的外壳函数。fixture中的代码可以定制,满足多变的测试需求,包括定义传入测试中的数据集、配置测试前系统的初始状态、为…

    技术杂谈 2023年7月25日
    075
  • 多标签多分类相关

    一、单标签多分类 单标签二分类这种问题是我们最常见的算法问题,主要是指label 标签的取值只有两种,并且算法中只有一个需要预测的label标签; 直白来讲就是每个实例的可能类别只…

    技术杂谈 2023年7月25日
    094
  • openFeign实现服务间并且调用时传递header以及新增header, header透传

    场景:A服务调用B服务,并且在进入到B服务之前,设置一个自定义的hader值,实现如下: 1、创建FeignConfiguration: import feign.Logger;i…

    技术杂谈 2023年5月30日
    079
  • classnames 和 css-module 一起使用

    common.less css;gutter:true; .server-btn-disabled { cursor: not-allowed; color: rgb(165, 1…

    技术杂谈 2023年5月30日
    081
  • Redrain个人维护并使用的DuiLib和UiLib库源代码下载地址

    首先说明一下Duilib和Uilib的差别:UiLIb是DuiLib是升级扩展版,UiLib添加了一些控件,比方渐变的FadeButton。而且增强了不少控件的功能和属性,比方托盘…

    技术杂谈 2023年5月31日
    087
  • 假设检验

    举个栗子。 我说我射击特别厉害,平均能打到8环,那么如何验证我是不是在吹牛逼呢,那就让我做几次射击看看我水平到底怎么样。 首先你选择相信我,假设我没吹牛,我的成绩在8环附近(这就是…

    技术杂谈 2023年5月31日
    075
  • 基于Golang的简易缓存系统实现

    github: https://github.com/jwcen/gocache本文来自博客园,作者:Jayvee,转载请注明原文链接:https://www.cnblogs.co…

    技术杂谈 2023年7月23日
    089
  • UOJTestRound#2社论

    模拟赛 C, D 出的 UTR 题,,, 开始复读官方题解 /oh/oh/oh 魔怔码风见谅 QwQ A. 题目排列顺序 给一个序列 ({f_n}),重排标准排列 (\pi),使得…

    技术杂谈 2023年7月24日
    065
  • freetype2 下载编译以及测试代码

    源码: https://sourceforge.net/projects/freetype/files/freetype2 下载解压后,进入源码目录执行cmake-gui,界面中配…

    技术杂谈 2023年6月1日
    097
  • 【源码笔记】FutureTask

    /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free s…

    技术杂谈 2023年7月24日
    068
  • 西西成语接龙小助手

    介绍 代码地址:https://github.com/taishan1994/chinese_chengyujielong 读完该文,你可以收获: python爬虫的简单使用。 构…

    技术杂谈 2023年6月1日
    080
  • 设计和开发时间配比

    分析、设计、调研文档编写时间和开发时间对开 一个人最好的习惯是独立思考、全面思考、深度思考、勤于思考、理性冷静、静坐沉思、定时反思、有仪式感、二分格物、三思而行、适量运动、适量饮食…

    技术杂谈 2023年5月31日
    0100
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球