Apple:Core Animation Programming Guide思维导图

1,125 阅读11分钟

点击这里下载原图

文章是XMind导出的MarkDown,不建议直接阅读      

Core Animation Programming Guide

About Core Animation

Core Animation Basics

Layer相当于包含位图信息和许多视觉相关属性的model

Like views, layers manage information about the geometry, content, and visual attributes of their surfaces. Unlike views, layers do not define their own appearance. A layer merely manages the state information surrounding a bitmap. The bitmap itself can be the result of a view drawing itself or a fixed image that you specify. For this reason, the main layers you use in your app are considered to be model objects because they primarily manage data.

Layer绘制会尽量使用GPU渲染,比view用CPU在主线程绘制更快

Core Animation passes the layer’s bitmap and state information to the graphics hardware, which does the work of rendering the bitmap using the new information. Manipulating the bitmap in hardware yields much faster animations than could be done in software. Because it manipulates a static bitmap, layer-based drawing differs significantly from more traditional view-based drawing techniques. With view-based drawing, changes to the view itself often result in a call to the view’s drawRect: method to redraw content using the new parameters. But drawing in this way is expensive because it is done using the CPU on the main thread. Core Animation avoids this expense by whenever possible by manipulating the cached bitmap in hardware to achieve the same or similar effects.

Layer的Moce、Scale、Rotate、Transparency、Corner radius、Background color会在硬件中完成帧绘制

Layer的几何计算是相对于Layer的anchor的

positon相当于anchorPoint坐标在父视图中的frame

图1:position和anchorPoint关系

图2:旋转和anchorPoint

Layer可以使用4x4的矩阵做translat、scale、rotate around * axis等操作

一个应用整体上会有三个Layer对象的集合

  • Model Layer Tree:目标动画值。

    The objects in this tree are the model objects that store the target values for any animations. Whenever you change the property of a layer, you use one of these objects.

  • Presentation Tree:正在进行动画的当前值(只读)。

    Objects in the presentation tree contain the in-flight values for any running animations. Whereas the layer tree objects contain the target values for an animation, the objects in the presentation tree reflect the current values as they appear onscreen. You should never modify the objects in this tree. Instead, you use these objects to read current animation values, perhaps to create a new animation starting at those values.

  • Render Tree:执行动画的私有属性。

    Objects in the render tree perform the actual animations and are private to Core Animation.

Layer与View关系

  • Layer使绘制和动画更高效
  • Layer不处理事件、绘制内容、参与到响应链

Setting Up Layer Objects

iOS默认启动Core Animation;OS X需要显式启用

改变与UIView关联的Layer对象

  • 重写layerClass改变view使用的Layer类型

    CAEmitterLayer使用来实现基于 Core Animation 的 particle emitter 系统。emitter layer 对象控制了 particles 的产生和它们的起点。 CAGradientLayer用来绘制一个填充 layer 对象的颜色渐变。 CAMetalLayer用来创建和提供 drawable textures,以使用 Metal 来渲染 layer 内容。 CAEAGLLayer/CAOpenGLLayer用来创建 backing store 和 context,以使用 OpenGL ES (iOS) 或 OpenGL (OS X) 渲染 layer 内容。 CAReplicatorLayer当你想要自动拷贝一个或多个 sublayers 时使用。replicator 会为你创建拷贝,并用你指定的属性来改变拷贝的外表或属性。 CAScrollLayer用来管理由多个 sublayers 组成的大的可滑动的区域。 CAShapeLayer用来绘制 cubic Bezier spline。Shape layers 对于绘制 path-based shapes 很有优势,因为它们总是导致一个 crip path,相对于你绘制到一个 layer 的backing store 中的 path,在伸缩的时候并不好看。然而 crisp 结果涉及到在主线程上渲染 the shape,并缓存结果。 CATextLayer用来渲染一个 plain 或 attributed 字符串。 CATiledLayer用来管理一个大的图片,这个大的图片可以分为很多小块,并支持单独的渲染,支持放大和缩小它的内容。 CATransformLayer用来渲染一个真 3D layer 层次,而不是其它 layer class 实现的 flattened layer 层次。 QCCompositionLayer用来村然一个 Quartz Composer composition (仅用于 OS X)

    • Your view draws content using Metal or OpenGL ES, in which case you would use a CAMetalLayer or CAEAGLLayer object.
    • There is a specialized layer class that offers better performance.
    • You want to take advantage of some specialized Core Animation layer classes, such as particle emitters or replicators.

提供一个Layer的内容

  • 将CGImageRef类型图片赋给layer的contents

  • 使用delegate提供Layer内容

    • displayLayer:方法
    • drawLayer:inContext:方法
  • 子类中重写绘制方法

    • display方法,直接设置contents
    • drawInContext方法,绘制内容到graphics context
  • 微调你提供的内容

    • contentsGravity:当图片赋给Layer的contents时,contentsGravity决定了图片如何适应当前的bounds
  • 与高分辨率的图片工作

    If you assign an image to a layer’s contents property, you must tell Core Animation about the image’s resolution by setting the layer’s contentsScale property to an appropriate value. The default value of the property is 1.0, which is appropriate for images intended to be displayed on standard resolution screens. If your image is intended for a Retina display, set the value of this property to 2.0.

    • 将图片赋给contents时,手动设置contentsScale

调节Layer的Visual Style 和 Appearance

  • Layer有自己的background和border

    • 设置layer的背景色为不透明的颜色时,将opaque设置为YES可以提高compositing Layer时的性能,消除Layer的backstore管理alpha channel的需要
    • 有圆角的话,一定不要标记一个Layer为opaque
  • Layers支持圆角

Animating Layer Content

改变Layer属性进行简单动画

  • 隐式动画会更新Layer对象的数据

  • 显示动画不会修改Layer tree中的数据

    • 显示动画只产生动画
    • 动画的最后,Core Animation会从Layer上移除动画对象
    • 然后使用Layer的当前值重绘
  • 动画与runloop

    • 隐式动画和显示动画通常在当前的run loop cycle结束后开始
    • 并且当前线程必须有一个run loop以便动画能够运行
    • 如果你修改了多个属性,或你添加了多个动画对象到一个 layer 的话,所有的这些属性改变会被同时做动画。

关键帧动画

  • 动画计时属性

    • calculationMode
    • keyTimes
    • timingFunctions

停止指定正在进行的动画

  • 使用removeAnimationForKey从Layer中移除animation对象

  • 使用removeAllAnimations移除所有正在进行的动画,使用Layer的当前信息重绘

    • 通常会带来外表的突然跳跃
    • 如果想让外表停留在动画最后帧的位置,可以使用presentation tree中的对象来获取最终的值,然后设置到layer tree中的对象上

同时进行多个动画

  • 使用CAAnimationGroup打包

检测动画的起止

  • setCompletionBlock:添加一个completion block到当前的transaction上
  • 赋一个delegate到CAAnimation对象,实现animationDidStart:和animationDidStop:finished:方法
  • 想要衔接两个动画,使用beginTime,不要用上述两种方法

Build a Layer Hierachy

Arranging Layers into a Layer Hierarchy

  • Adding Layers

    • addSublayer:
  • Inserting Layers

    • insertSublayer:above:
    • insertSublayer:atIndex:
    • insertSublayer:below:
  • Removing Layers

    • removeFromSuperlayer
  • Exchanging Layers

    • replaceSublayer:with

Always use integral numbers for the width and height of your layer.

Layer间坐标转换

  • convertPoint:fromLayer:
  • convertPoint:toLayer:
  • convertRect:fromLayer:
  • convertRect:toLayer:
  • convertTime:fromLayer:
  • convertTime:toLayer:

Advanced Animation Tricks

CATransition转场动画

Timing

  • CAAnimation指定动画时间

  • CALayer配置timing相关特性

  • 一个Layer的local time被parent layers或自己的timing parameters改变

    • 例如Layer的speed属性导致这个Layer(包含它的sublayers)上的动画按比例改变
  • CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];

暂停和恢复动画

  • -(void)pauseLayer:(CALayer*)layer { CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; layer.speed = 0.0; layer.timeOffset = pausedTime; }
    • (void)resumeLayer:(CALayer*)layer { CFTimeInterval pausedTime = [layer timeOffset]; layer.speed = 1.0;layer.timeOffset = 0.0; layer.beginTime = 0.0; CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; layer.beginTime = timeSincePause; }

Changing a Layer's Default Behavior

自定义遵循CAAction协议的Action对象

必须写明Action对象如何被触发

  • 关联actions对象到自定义或layer的任何一个属性上

    • 标识这个action对象的key是这个属性的name
  • layer became visible 或者添加到一个layer hierachy

    • 标识这个action的key是kCAOnOrderIn
  • layer从一个layer hierarchy中移除

    • kCAOnOrderOut
  • layer将要涉及到一个transition动画

    • kCATransition

Core Animation搜寻action对象顺序

  • 1.Layer的delegate实现的actionForLayer:forKey:方法

    • 基于给定的key返回一个action对象
    • 如果它不处理这个action返回nil,这种情况下继续搜索
    • 返回NSNull对象,这时搜索立即停止
  • 2.Layer对象在他的actions字典中查找给定的key

  • 3.layer查找style字典,看是否有一个actions字典包含给定的key

  • 4.layer调用它的defaultActionForKey:方法

  • 5.Layer执行Core Animation定义的隐式action

在上述任何一个搜索点提供一个action对象,Layer会停止它的搜索,并执行返回的action对象

  • runActionForKey:object:arguments

何时插入action对象依赖于想要如何修改你的Layer

  • 特定环境下使用的actions,或者已经使用delegate,提供一个delegate并实现它的actionForLayer:forKey:方法
  • 对于不常使用代理的Layer对象,添加action到Layer的actions字典中
  • 对于自定义属性相关的action对象,添加action到Layer的style字典中
  • 对于Layer行为的基础acitons,集成Layer,重写方法defaultActionForKey:

使用CATransaction Class临时禁用actions

  • [CATransaction begin]; [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; [aLayer removeFromSuperlayer]; [CATransaction commit];

Improving Animation Performance

Use Opaque Layers Whenever Possible

设置 layer 的 opacity 属性为 YES,让 Core Animation 知道它不需要维护 layer 的 alpha channel。没有 alpha channel 意味着 compositor 不需要混合这个 layer 后面的内容,这在渲染的时候可以节约时间。然而,这个属性主要是对于 layer-backed view 的 layer 和 Core Animation 负责创建 layer 潜在内容的 layer 而言的,对于 layer 的 contents 是图片的是情况,图片的 alpha channel 总是被保存的,不论 opacity 属性的值是多少。

  • 对于Layer的contents是图片的情况不生效,图片的alpha channel总是被保存

Use Simpler Paths for CAShapeLayer Objects

The CAShapeLayer class creates its content by rendering the path you provide into a bitmap image at composite time. The advantage is that the layer always draws the path at the best possible resolution but that advantage comes at the cost of additional rendering time. If the path you provide is complex, rasterizing that path might get too expensive. And if the size of the layer changes frequently (and thus must be redrawn frequently), the amount of time spent drawing can add up and become a performance bottleneck. One way to minimize drawing time for shape layers is to break up complex shapes into simpler shapes. Using simpler paths and layering multiple CAShapeLayer objects on top of one another in the compositor can be much faster than drawing one large complex path. That is because the drawing operations happen on the CPU whereas compositing takes place on the GPU. As with any simplifications of this nature, though, the potential performance gains are dependent on your content. Therefore, it is especially important to measure the performance of your code before optimizing so that you have a baseline to use for comparisons.

Set the Layer Contents Explicitly for Identical Layers

If you are using the same image in multiple layer objects, load the image yourself and assign it directly to the contents property of those layer objects. Assigning an image to the contents property prevents the layer from allocating memory for a backing store. Instead, the layer uses the image you provide as its backing store. When several layers use the same image, this means that all of those layers are sharing the same memory rather than allocating a copy of the image for themselves. 如果你在多个 layer 中使用相同的图片的话,手动加载这张图片,直接将它赋给这些 layer 对象的 contents 属性。赋一个图片给 contents 属性阻止 layer 给 backing store 分配内存。相反,layer 使用你提供的 image 作为它的 backing store。当多个 layers 使用相同的图片时,这种方式使得这些 layers 对象使用相同的内存而不是它们每个一个 copy。

Always Set a Layer's Size to Integral Values

For best results, always set the width and height of your layer objects to integral values. Although you specify the width and height of your layer’s bounds using floating-point numbers, the layer bounds are ultimately used to create a bitmap image. Specifying integral values for the width and height simplifies the work that Core Animation must do to create and manage the backing store and other layer information. 为了最好的结果,始终设置 layer 的 width 和 height 为整数值。尽管你可以指定 layer 的 width 和 height 为浮点数,layer bounds 最终被用来创建一个 bitmap image。为 layer 的 width 和 height 指定整数简化了 Core Animation 创建和管理 backing store 和其他 layer 信息等必须做的工作。

Use Asynchronous Layer Rendering As Needed

Any drawing that you do in your delegate’s drawLayer:inContext: method or your view’s drawRect: method normally occurs synchronously on your app’s main thread. In some situations, though, drawing your content synchronously might not offer the best performance. If you notice that your animations are not performing well, you might try enabling the drawsAsynchronously property on your layer to move those operations to a background thread. If you do so, make sure your drawing code is thread safe. And as always, you should always measure the performance of drawing asynchronously before putting it into your production code. 任何你在 layer 的 delegate 方法 drawLayer:inContext: 或你视图的 drawRect: 方法中做的绘制通常同步的在主线程上发生。某些场合,同步绘制内容可能并不提供最好的性能。如果你注意到动画有卡顿,你也许会启用 drawsAsynchronously 属性来将这些绘制操作移至后台线程。如果你这么做的话,保证你的绘制代码是线程安全的。同样,请测量你的性能改变。

Specify a Shadow Path When Adding a Shadow to Your Layer

Letting Core Animation determine the shape of a shadow can be expensive and impact your app’s performance. Rather than letting Core Animation determine the shape of the shadow, specify the shadow shape explicitly using the shadowPath property of CALayer. When you specify a path object for this property, Core Animation uses that shape to draw and cache the shadow effect. For layers whose shape never changes or rarely changes, this greatly improves performance by reducing the amount of rendering done by Core Animation. 让 Core Animation 决定一个 shadow 的 shape 很昂贵并影响你应用的性能。与其让 Core Animation 决定 shadow 的 shape,不如使用 layer 的 shadowPath 属性显式指定 shadow 的 shape。当你为这个属性指定一个 path 对象时,Core Animation 使用这个 shape 来绘制并缓存 shadow effect。对于这些 shape 从不改变的 layers,这样做会大大提升性能,因为这样做减少了 Core Animation 所需做的渲染。