CoreAnimation编程指南(一)

官方文档

关于CoreAnimation

  • CoreAnimation是 iOS和OS X的图形渲染的基础框架,它将大部分的图形绘制工作直接交给图形硬件来处理,图形硬件会加速图形渲染,具有更高的图形渲染能力,转移CPU的压力.
  • 它在系统框架层次中的位置如下:
  • 实际开发中,大都使用UIKit基本能满足动画需求,了解CoreAnimation底层原理,有助于我们更好的了解上层API的调用,并优化和避免一些性能上的问题

CoreAnimation的功能大纲

  • 管理App的内容显示: 核心动画本身并不是一个绘图系统,它管理着是图的合成,它是一个管理图层内容和操作图形硬件的基础框架,通过对图层的操作来影响最终绘制的内容,通过图层将内容捕获到bitmap中,这样硬件就能够方便的进行操作.图层主要用于管理是图内容,实际开发时也可以对图层进行调整如创图层,设置图层属性,调整图层位置,以及他们的绘制线程等等。

  • 图层修改并生成动画: 大都输的动画可以通过直接修改图层属性来完成,例如视图的bounds,opacity,transform,position,以及一些它可视化能被修改的属性 对于大多数这些特性,更改特性的值将导致创建隐式动画,从而使层从旧值设置为新值; 在需要对生成的动画行为进行更多控制的情况下,也可以显式地设置这些属性的动画。

  • 图层可以组织成层次结构: 可以排列图层创建一个图层树,图层的排列顺序以及层级将会影响他们最终所展示的内容,附着到视图的一组图层的层次结构反映了相应的视图层次结构。还可以将独立层添加到层层次结构中,以将应用程序的可视内容扩展到视图之外。

  • 操作可以更改层的默认行为: 隐式层动画是使用动作对象实现的,动作对象是实现预定义接口的通用对象。核心动画使用动作对象实现通常与层关联的默认动画集。您可以创建自己的动作对象来实现自定义动画,也可以使用它们来实现其他类型的行为。然后将动作对象指定给图层的某个特性。当该属性更改时,核心动画将检索您的操作对象并告诉它执行其操作。

核心动画基础

  • 核心动画提供了一个通用系统,用于动画视图和应用程序的其他视觉元素。核心动画不能替代应用程序的视图。相反,它是一种与视图集成的技术,可以提供更好的性能和对内容动画的支持。它通过将视图内容缓存到位图中来实现这一行为,位图可以由图形硬件直接操作。在某些情况下,这种缓存行为可能需要您重新考虑如何显示和管理应用程序的内容,但大多数情况下,您在使用核心动画时却不知道它在那里。除了缓存视图内容外,核心动画还定义了一种方法来指定任意的可视内容,将该内容与视图集成,并将其与其他所有内容一起设置动画。

  • 您可以使用核心动画来设置对应用程序视图和可视对象的更改。大多数更改都与修改可视对象的属性有关。

  • 图层为绘图和动画提供了基础: 层对象是在三维空间中组织的二维曲面,是核心动画所做的一切的核心。与视图一样,图层管理有关其曲面的几何体内容视觉属性的信息。与视图不同,图层不定义自己的外观。层仅仅管理位图周围的状态信息。位图本身可以是视图图形本身或指定的固定图像的结果。因此,应用程序中使用的主要层被视为模型对象,因为它们主要管理数据。记住这个概念很重要,因为它会影响动画的行为.

  • 基于图层的绘图模型: 大多数图层不会在你的应用程序中绘制任何实际的图形。相反,层会捕获应用程序提供的内容并将其缓存在位图中,位图有时也称为后台存储。当随后更改图层的特性时,所做的就是更改与图层对象关联的状态信息。当更改触发动画时,核心动画将层的位图和状态信息传递给图形硬件,图形硬件使用新信息渲染位图,如图1-1所示。在硬件中操作位图比在软件中可以产生更快的动画效果。由于它操作静态位图,基于层的绘制与更传统的基于视图的绘制技术有很大不同。在基于draw的视图中,经常使用基于draw的方法调用新的视图参数。但是用这种方式绘制是昂贵的,因为它是使用主线程上的CPU完成的。核心动画通过在硬件中操纵缓存的位图来达到相同或相似的效果,从而避免了这种开销。虽然核心动画尽可能多地使用缓存内容,但应用程序仍必须提供初始内容并不时更新。你的应用程序有几种方法可以为层对象提供内容,这些方法在提供层的内容中有详细描述。

  • 基于图层的动画: 层对象的数据和状态信息与该层内容在屏幕上的可视化表示分离。这种解耦为核心动画提供了一种插入自身的方法,并使从旧状态值到新状态值的变化具有动画效果。例如,更改层的位置属性会导致核心动画将层从其当前位置移动到新指定的位置。对其他属性的类似更改会导致相应的动画。图1-2说明了一些可以在图层上执行的动画类型。用于触发动画的图层特性列表

  • 图层的几何信息定义: 图层的工作之一是管理其内容的可视几何图形。视觉几何包含有关内容边界、其在屏幕上的位置以及层是否以任何方式旋转缩放变换的信息。与视图类似,层具有边框和边框矩形,可用于定位层及其内容图层还具有视图所不具有的其他特性,例如定位点,它定义了围绕其进行操纵的点。指定图层几何图形某些方面的方式也不同于为视图指定该信息的方式。如bounds和frame

  • 图层使用两种类型的坐标系

    • iOS起点在左上角
    • OS X起点在左下角
    • 由于使用同一个CoreAnimation,所以我们需要注意坐标系的差异,处理iOS时注意Y轴的反转
  • 图层基于锚点的单元坐标系

核心动画基础-锚点

  • 从下面的图来看,锚点类似于一个钉子,将视图定在上面,Position的位置和锚点的点位相同,只不过Position是相对于父是图的位置,而锚点是相对于自身的位置,当进行旋转变换时锚点和位置均不回变动,放大时位置会变动,基于二维平面任何一个轴变换时Postion也会跟着变化


  • 层可以在三维空间中操作: 每个层都有两个变换矩阵,可以用来操纵层及其内容。CALayer的transform属性指定要同时应用于层及其嵌入子层的变换。通常,当要修改图层本身时,可以使用此特性。例如,可以使用该特性来缩放或旋转图层或临时更改其位置。sublayerTransform属性定义仅适用于子层的附加转换,最常用于向场景内容添加透视视觉效果。 变换的工作原理是将坐标值乘以一个数字矩阵,以获得表示原始点的变换版本的新坐标。因为核心动画值可以在三维空间中指定,每个坐标点都有四个值,这些值必须乘以一个四乘四矩阵,如图1-7所示。在核心动画中,图形中的变换由CATTransferM3D类型表示。幸运的是,您不必直接修改此结构的字段来执行标准转换。核心动画为创建缩放、平移和旋转矩阵以及进行矩阵比较提供了一整套功能。除了使用函数操纵变换之外,核心动画还扩展了键值编码支持,允许您使用关键路径修改变换。对于可以修改的关键路径列表

  • 图1-8显示了一些更常见的转换的矩阵配置。将任何坐标乘以单位变换将返回完全相同的坐标。对于其他变换,坐标的修改方式完全取决于更改的矩阵分量。例如,若要仅沿x轴平移,则需要为平移矩阵的tx分量提供非零值,并将ty和tz值保留为0。对于旋转,将提供目标旋转角度的适当正弦和余弦值。

核心动画基础-图层树

  • 使用核心动画的应用程序有三组层对象。在使应用程序的内容显示在屏幕上的过程中,每一组层对象都有不同的角色:

    • 模型层树:(或简单的“层树”)中的对象是应用程序与之交互最多的对象。此树中的对象是存储任何动画的目标值的模型对象。无论何时更改图层的特性,都可以使用这些对象之一。
    • 表示树: 表示树中的对象包含任何正在运行的动画的正在运行的值。虽然层树对象包含动画的目标值,但表示树中的对象在屏幕上显示时会反映当前值不应修改此树中的对象。相反,您可以使用这些对象读取当前动画值,也许可以从这些值开始创建新动画。
    • 渲染树: 渲染树中的对象执行实际动画,是核心动画的专用对象。
  • 每一组层对象都被组织成一个层次结构就像应用程序中的视图一样。事实上,对于为所有视图启用层的应用程序,每个树的初始结构与视图层次结构完全匹配。但是,应用程序可以根据需要将其他层对象(即与视图无关的层)添加到层层次结构中。在不需要视图所有开销的情况下,您可能会这样做,以优化应用程序的性能。图1-9显示了在一个简单的iOS应用程序中发现的层的分解。示例中的窗口包含一个内容视图,它本身包含一个按钮视图和两个独立的图层对象。每个视图都有一个相应的图层对象,该对象构成图层层次结构的一部分。

  • 对于层树中的每个对象,在表示树和渲染树中都有一个匹配的对象,如图1-10所示。如前所述,应用程序主要处理层树中的对象,但有时可能访问表示树中的对象。具体来说,访问层树中对象的presentationLayer属性将返回表示树中相应的对象。您可能需要访问该对象以读取动画中间属性的当前值。

    • 展示树中层只能在动画执行过程中访问它的属性,只读,它是包含了动画过程中每个时刻值

图层与视图之间的关系

  • 图层不能替代应用程序的视图,也就是说,不能仅基于图层对象创建可视界面。
  • 图层为视图提供基础结构。具体地说,层使绘制视图内容和动画更容易和更有效,同时保持较高的帧速率。
  • 图层不处理事件、绘制内容、参与响应程序链或执行许多其他操作。因此,每个应用程序都必须有一个或多个视图来处理这些类型的交互。

  • 在iOS中,每个视图都由相应的layer对象支持但是在osx中,您必须决定哪些视图应该有层。在以后的v10.0版本中,可能会添加到所有的视图中。但是,您不需要这样做,并且在开销不必要的情况下仍然可以禁用层。层确实会在一定程度上增加应用程序的内存开销但它们的好处往往大于缺点,因此最好在禁用层支持之前测试应用程序的性能。

  • 尽量修改视图,而不是修改图层,避免在OS X系统可能带来一些潜在的问题

  • 除了与视图关联的图层外,还可以创建没有相应视图的图层对象。您可以将这些独立层对象嵌入到应用程序中的任何其他层对象中,包括与视图关联的对象。通常将单独的路径用作对象优化的一部分。例如,如果要在多个位置使用同一个图像,可以加载该图像一次并将其与多个独立图层对象关联,然后将这些对象添加到图层树中。然后每个层引用源图像,而不是尝试在内存中创建该图像的自己的副本。

设置图层对象

  • 层对象是核心动画的核心。层管理应用程序的可视内容,并提供用于修改该内容的样式和视觉外观的选项。虽然iOS应用程序自动启用了层支持,但OSX应用程序的开发人员必须先明确启用它,然后才能利用性能优势。启用后,您需要了解如何配置和操作应用程序的层以获得所需的效果。
  • 在应用程序中启用核心动画支持
    • 链接到QuartzCore框架。(只有在明确使用核心动画接口时,iOS应用程序才必须链接到此框架。)
    • 通过执行以下操作之一,为一个或多个NSView对象启用层支持:
      • 在nib文件中,使用视图效果检查器为视图启用图层支持。检查器显示选定视图及其子视图的复选框。建议尽可能在窗口的“内容”视图中启用层支持。
      • 对于以编程方式创建的视图,请调用视图的setWantsLayer:方法并传递值YES,以指示视图应使用层。
  • 更改与视图关联的图层对象:默认情况下,基于图层的视图创建CALayer类的实例,在大多数情况下,您可能不需要其他类型的图层对象。但是,核心动画提供了不同的层类,每个类都提供了一些有用的特殊功能选择不同的层类可能使您能够以简单的方式提高性能或支持特定类型的内容。例如,CATiledLayer类被优化为以高效的方式显示大图像

  • 更改UIView使用的图层类: 通过重写iOS视图的layerClass方法并返回不同的类对象,可以更改iOS视图使用的层类型。大多数iOS视图创建一个CALayer对象,并将该层用作其内容的后备存储。对于大多数您自己的视图,这个默认选择是一个很好的选择,您不需要更改它。但您可能会发现,在某些情况下,使用不同的层类更合适。例如,在以下情况下,可能需要更改图层类:

    • 您的视图使用Metal或OpenGL ES绘制内容,在这种情况下,您将使用CAMetalLayerCAEAGLLayer对象。
    • 有一个专门的层类可以提供更好的性能。
    • 您需要利用一些特殊的核心动画层类,例如粒子发射器复制器Objective-C + (Class) layerClass {
      return [CAMetalLayer class];
      }
  • 更改NSView使用的图层类: 重写makebacklayer方法可以更改由makebacklayer使用的对象。在该方法的实现中,创建并返回希望AppKit用于支持自定义视图的layer对象。在需要使用自定义层(如滚动层或平铺层)的情况下,可以重写此方法

  • 层托管允许您在OSX中更改层对象:

    [myView setWantsLayer:YES];
    CATiledLayer* hostedLayer = [CATiledLayer layer];
    [myView setLayer:hostedLayer];

不同的层类提供专门的行为

  • 核心动画定义了许多标准层类,每个类都是为特定的用例而设计的。CALayer类是所有层对象的根类。它定义了所有图层对象必须支持的行为,并且是图层支持视图使用的默认类型。但是,您也可以指定表2-1中的一个图层类。

    • CAEmitterLayer:用于实现基于核心动画的粒子发射器系统。发射器层对象控制粒子及其原点的生成。
    • CAGradientLayer: 用于绘制填充图层形状的颜色渐变(在任何圆角范围内)。
    • CAMetalLayer: 用于设置和绘制纹理,以使用金属渲染层内容。
    • CAEAGLLayer/CAOpenGLLayer: 用于设置使用OpenGL ES(iOS)或OpenGL(OS X)呈现层内容的备份存储和上下文。
    • CAReplicatorLayer: 当要自动复制一个或多个子图层时使用。复制器为您制作副本,并使用您指定的属性来更改副本的外观或属性。
    • CAScrollLayer: 用于管理由多个子层组成的大的可滚动区域。
    • CAShapeLayer: 用于绘制三次贝塞尔样条曲线。形状层对于绘制基于路径的形状非常有利,因为它们总是生成一个清晰的路径,而不是将路径绘制到层的后备存储中,当缩放时,该路径看起来不太好。但是,清晰的结果确实涉及到在主线程上渲染形状并缓存结果。
    • CATextLayer: 用于呈现纯文本或属性化文本字符串。
    • CATiledLayer: 用于管理大图像,该图像可划分为较小的分幅并单独渲染,支持放大和缩小内容。
    • CATransformLayer: 用于渲染真实的3D层层次,而不是由其他层类实现的平坦层层次。
    • QCCompositionLayer: 渲染 Quartz Composer composition. (OS X only)
  • 提供层的内容: 层是管理应用程序提供的内容的数据对象。层的内容由包含要显示的可视数据的位图组成。可以通过以下三种方法之一提供该位图的内容:

    • 将图像对象直接指定给图层对象的“内容”特性。(此技术最适用于从不更改或很少更改的层内容。)
    • 将代理对象指定给层,并让代理绘制层的内容。(此技术最适用于可能会定期更改并且可以由外部对象(如视图)提供的图层内容。)
    • 定义一个layer子类并重写它的一个绘图方法来自己提供层内容。(如果无论如何都必须创建自定义图层子类,或者要更改图层的基本绘图行为,则此技术适用。)

    • 为层内容使用图像: 指定给图层的图像必须是CGImageRef类型。分配图像时,请记住提供分辨率与本机设备分辨率匹配的图像。对于具有Retina显示的设备,这可能还需要调整图像的contentsScale属性。

    • 使用委托提供层的内容:

    • 如果委托实现displayLayer:方法,则该实现负责创建位图并将其分配给层的contents属性。

    • 如果您的委托实现drawLayer:inContext:方法,核心动画创建位图,创建图形上下文以绘制到该位图中,然后调用委托方法填充位图。您的委托方法所要做的就是绘制到所提供的图形上下文中。

  • 对于具有自定义内容的图层支持视图,应继续替代视图的方法来绘制图形基于层的视图会自动将其自身作为其层的委托并实现所需的委托方法,您不应更改该配置。相反,您应该实现视图的drawRect:方法来绘制内容。

  • 通过子类化提供层内容:

    • 重写图层的display方法,并使用它直接设置图层的“内容”特性。
    • 重写图层的drawInContext:方法并使用它绘制到提供的图形上下文中。
  • 调整您提供的内容: 将图像指定给层的contents属性时,该层的contentsGravity属性将确定如何操纵该图像以适应当前边界。默认情况下,如果图像大于或小于当前边界,层对象将缩放图像以适合可用空间。如果层边界的纵横比与图像的纵横比不同,这可能会导致图像失真。您可以使用contentsGravity属性来确保您的内容以最佳方式呈现。

    • 基于位置的重力常数允许您将图像固定到层边界矩形的特定边或角上,而无需缩放图像。
    • 基于缩放的重力常数允许您使用几个选项中的一个来拉伸图像,其中一些选项保留纵横比,而另一些选项则没有。
    • 图2-2显示了基于比例的重力常数如何影响图像。如果图像不完全符合层的边界矩形,则所有这些常量都会缩放图像。两种模式之间的区别在于它们如何处理图像的原始纵横比。有些模式会保留它,而其他模式则不会。默认情况下,层的contentsGravity属性设置为kCAGravityResize常量,这是唯一不保留图像纵横比的模式。
  • **使用高分辨率图像: **层对底层设备屏幕的分辨率没有任何固有的了解。层只是存储一个指向位图的指针,并在给定可用像素的情况下以最佳方式显示它。如果将图像指定给层的“内容”属性,则必须通过将层的“内容缩放”属性设置为适当的值来告诉核心动画有关图像的分辨率。该属性的默认值为1.0,适用于要在标准分辨率屏幕上显示的图像。如果图像用于视网膜显示,请将此属性的值设置为2.0。

调整图层的视觉样式和外观

  • 图层对象具有内置的视觉装饰,例如边框和背景色,可以用来补充图层的主要内容。由于这些视觉装饰不需要在零件上进行任何渲染,因此在某些情况下可以将层用作独立实体。你所要做的就是在图层上设置一个属性,图层处理必要的图形,包括任何动画。有关这些视觉装饰如何影响层外观的其他插图
  • 除了基于图像的内容外,图层还可以显示填充的背景和笔划的边框。背景色呈现在层内容图像的后面,边框呈现在该图像的顶部,如图2-3所示。如果图层包含子图层,它们也会显示在边界下方。因为背景色位于图像的后面,所以该颜色会穿透图像的任何透明部分

  • 设置图片时需要坐标系统反转y

  • 如果将图层的背景色设置为不透明,请考虑将图层的“不透明”属性设置为“是”。这样做可以提高在屏幕上合成层时的性能,并且不需要层的后台存储来管理alpha通道。但是,如果图层的角半径也不为零,则不能将其标记为不透明。

  • 层支持角半径: 您可以通过添加角半径来为层创建圆角矩形效果。角半径是一种视觉装饰,它屏蔽了层边界矩形的一部分角,以允许底层内容显示出来,如图2-4所示。因为它涉及到应用透明度遮罩,所以除非masksToBounds特性设置为“是”否则角半径不会影响层的“内容”特性中的图像。但是,角点半径总是影响图层的背景色和边框的绘制方式。

  • Shadows: 当向层添加阴影时,阴影是层内容的一部分,但实际上延伸到层边界矩形之外。因此,如果为层启用masksToBounds特性,阴影效果将围绕边剪裁。如果图层包含任何透明内容,这可能会导致一种奇怪的效果,即直接位于图层下方的阴影部分仍然可见,但超出图层的部分则不可见。如果你想要一个阴影同时又想使用边界遮罩,你可以用两层而不是一层。将蒙版应用于包含内容的层,然后将该层嵌入到启用了阴影效果的完全相同大小的第二层中

  • 过滤器为OS X视图添加视觉效果: 在OSX应用程序中,可以将核心图像过滤器直接应用于层的内容。您可以这样做来模糊或锐化图层的内容、更改颜色、扭曲内容或执行许多其他类型的操作。例如,图像处理程序可以使用这些滤波器以非破坏性方式修改图像,而视频编辑程序可以使用它们来实现不同类型的视频过渡效果。而且,由于过滤器应用于硬件层的内容,渲染速度快且平滑。

    • 通过将CIFilter对象添加到层的以下属性来指定筛选器:
    • 过滤器属性包含一个过滤器数组,这些过滤器只影响图层的前景内容。
      • backgroundFilters属性包含只影响层背景内容的筛选器数组。
      • compositingFilter属性定义如何将层的前景和背景内容合成在一起。
      • 要向层添加筛选器,必须首先找到并创建CIFilter对象,然后在将其添加到层之前对其进行配置。CIFilter类包括几个用于查找可用核心映像筛选器的类方法,例如filterWithName:方法。不过,创建过滤器只是第一步。许多过滤器都有定义过滤器如何修改图像的参数。例如,长方体模糊过滤器具有影响应用模糊量的输入半径参数。作为过滤器配置过程的一部分,您应该始终为这些参数提供值。但是,一个不需要指定的公共参数是输入图像,它由层本身提供。
      • 向图层添加过滤器时,最好在将过滤器添加到图层之前配置过滤器参数。这样做的主要原因是,一旦添加到层中,就不能修改CIFilter对象本身。但是,可以使用层的设置值:forKeyPath:方法更改筛选器值。
    • 清单2-6展示了如何创建一个夹点失真过滤器并将其应用于层对象。此过滤器将层的源像素向内收缩,对最靠近指定中心点的像素进行最大程度的扭曲。请注意,在示例中,您不需要为过滤器指定输入图像,因为层的图像是自动使用的。Filters
  • 向图层添加自定义特性: CAAnimation和CALayer类扩展了键值编码约定,以支持自定义属性。可以使用此行为将数据添加到图层并使用定义的自定义键检索数据。甚至可以将操作与自定义特性相关联,以便在更改特性时执行相应的动画。

设置图层内容动画

核心动画提供的基础设施使您可以轻松创建应用程序层的复杂动画,并扩展到拥有这些层的任何视图。例如,更改层框架矩形的大小、更改其在屏幕上的位置、应用旋转变换或更改其不透明度。对于核心动画,初始化动画通常与更改属性一样简单,但也可以创建动画并显式设置动画参数

  • 修改图层属性的简单动画:

    • 根据实际需求可以创建显示动画和隐式动画,隐式动画使用默认的计时动画属性来执行动画,而显式动画要求您使用动画对象自己配置这些属性。因此,隐式动画非常适合于那些不需要大量代码就可以进行更改的情况,并且默认的计时非常适合您。
    • 简单的动画包括改变一个层的属性,让核心动画随着时间的推移而改变。图层定义了许多影响图层可见外观的特性。更改其中一个属性是设置外观更改动画的一种方法。例如,将图层的不透明度从1.0更改为0.0会导致图层淡出并变为透明。
    • 要触发隐式动画,只需更新层对象的属性。在图层树中修改图层对象时,这些对象会立即反映您的更改。但是,图层对象的视觉外观不会立即更改。相反,核心动画使用您的更改作为触发器来创建和调度一个或多个隐式动画以供执行。因此,进行如清单3-1所示的更改会导致Core Animation为您创建一个动画对象,并安排该动画在下一个更新周期开始运行。
    • 要使用动画对象显式地进行相同的更改,需要创建一个CABasicAnimation对象并使用该对象配置动画参数在将动画添加到层之前,可以设置动画的开始值和结束值、更改持续时间或更改任何其他动画参数。清单3-2展示了如何使用动画对象淡出层。创建对象时,为要设置动画的特性指定关键点路径,然后设置动画参数。若要执行动画,请使用“添加”动画:addAnimation:forKey:方法将其添加到要设置动画的层。

      • 通过显示动画执行透明度改变

        CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];
        fadeAnim.fromValue = [NSNumber numberWithFloat:1.0];
        fadeAnim.toValue = [NSNumber numberWithFloat:0.0];
        fadeAnim.duration = 1.0;
        [theLayer addAnimation:fadeAnim forKey:@"opacity"];

    // Change the actual data value in the layer to the final value.
    theLayer.opacity = 0.0;
    ```
    - 注意: 创建显式动画时,建议始终为动画对象的fromValue属性指定值。如果不为此特性指定值,则核心动画将使用层的当前值作为起始值。如果已将属性更新为其最终值,则可能无法获得所需的结果

构建图层的层次结构

  • 在你的应用程序中,最好的方式就是在视图中使用它们。但是,有时可能需要通过向视图层次添加其他图层对象来增强视图层次。如果这样做可以提供更好的性能,或者允许您实现单独使用视图很难实现的功能,则可以使用层。在这些情况下,您需要知道如何管理所创建的层层次结构。
  • 将层排列到层层次结构中: 层层次结构在许多方面与查看层次结构相似。将一个层嵌入另一层中,以在嵌入的层(称为子层)和父层(称为超层)之间创建父子关系。这种父子关系影响子层的各个方面。例如,其内容位于其父对象的内容之上,其位置相对于其父对象的坐标系指定,并且受应用于父对象的任何变换的影响
  • Adding, Inserting, and Removing Sublayers:

    • 添加和插入子层时,必须先设置子层的大小和位置,然后它才会显示在屏幕上。在将子层添加到层层次结构后,可以修改子层的大小和位置,但应该养成在创建层时设置这些值的习惯。
    • 使用bounds属性设置子层的大小,并使用position属性设置子层在其父层中的位置。边界矩形的原点几乎总是(0,0),其大小是您希望在点中指定的层的任何大小。位置特性中的值是相对于图层的定位点(默认情况下位于图层中心)进行解释的。如果不为这些特性指定值,则核心动画会将层的初始宽度和高度设置为0,并将位置设置为(0,0)。

      myLayer.bounds = CGRectMake(0, 0, 100, 100);
      myLayer.position = CGPointMake(200, 200);
      

  • 层层次如何影响动画:

    • 某些超层特性可以影响应用于其子层的任何动画的行为。其中一个特性是速度特性,它是动画速度的倍增。默认情况下,此属性的值设置为1.0,但将其更改为2.0会导致动画以其原始速度的两倍运行,从而在一半时间内完成。此属性不仅影响为其设置属性的图层,还影响该图层的子图层。这种变化也是乘法的。如果子层及其父层的速度都为2.0,则子层上的动画将以其原始速度的四倍运行。
    • 大多数其他层的变化以可预测的方式影响任何包含的子层。例如,将旋转变换应用于层将旋转该层及其所有子层。类似地,更改层的不透明度会更改其子层的不透明度。对层大小的更改遵循调整层层次结构布局中描述的布局规则。
  • 调整层层次结构的布局:

    • 核心动画支持多个选项来调整子层的大小和位置,以响应对其超层的更改。在iOS中,层支持视图的普遍使用使得层层次结构的创建变得不那么重要;只支持手动布局更新。对于OSX,还提供了其他几个选项,使您更容易管理层层次结构。
    • 仅当使用创建的独立图层对象构建图层层次时,图层级别布局才相关。如果应用程序的层都与视图关联,请使用基于视图的布局支持来更新视图的大小和位置以响应更改
  • 使用约束来管理OSX中的层层次结构

    • 创建一个或多个CAConstraint对象。使用这些对象来定义约束参
    • 将约束对象添加到修改其属性的层。
    • 检索共享的CAConstraintLayoutManager对象并将其分配给直接超层。
    • 图4-1显示了可用于定义约束的属性及其影响的层的方面。可以使用约束根据层的中点边缘相对于另一个层的位置来更改层的位置。也可以使用它们更改图层的大小。所做的更改可以与超图层成比例,也可以相对于另一个图层。您甚至可以向结果更改添加比例因子或常量。这种额外的灵活性使得使用一组简单的规则可以非常精确地控制层的大小和位置。

      [myLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY relativeTo:@"superlayer" 
      attribute:kCAConstraintMidY]];
      
      • 层布局示例
    // Create and set a constraint layout manager for the parent layer.
    theLayer.layoutManager=[CAConstraintLayoutManager layoutManager];
    

// Create the first sublayer.
CALayer *layerA = [CALayer layer];
layerA.name = @"layerA";
layerA.bounds = CGRectMake(0.0,0.0,100.0,25.0);
layerA.borderWidth = 2.0;

// Keep layerA centered by pinning its midpoint to its parent's midpoint.
[layerA addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY
relativeTo:@"superlayer"
attribute:kCAConstraintMidY]];
[layerA addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX
relativeTo:@"superlayer"
attribute:kCAConstraintMidX]];
[theLayer addSublayer:layerA];

// Create the second sublayer
CALayer *layerB = [CALayer layer];
layerB.name = @"layerB";
layerB.borderWidth = 2.0;

// Make the width of layerB match the width of layerA.
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth
relativeTo:@"layerA"
attribute:kCAConstraintWidth]];

// Make the horizontal midpoint of layerB match that of layerA
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX
relativeTo:@"layerA"
attribute:kCAConstraintMidX]];

// Position the top edge of layerB 10 points from the bottom edge of layerA.
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY
relativeTo:@"layerA"
attribute:kCAConstraintMinY
offset:-10.0]];

// Position the bottom edge of layerB 10 points
// from the bottom edge of the parent layer.
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY
relativeTo:@"superlayer"
attribute:kCAConstraintMinY
offset:+10.0]];

[theLayer addSublayer:layerB];
```

  • 为OSX层层次结构设置自动调整大小规则

    • 自动调整大小规则是在OS X中调整层大小和位置的另一种方法。使用自动调整规则,您可以指定层的边缘与超级层的相应边缘保持固定或可变的距离。同样,可以指定图层的宽度或高度是固定的还是可变的。关系总是在层和它的超层之间。不能使用自动调整大小规则来指定同级层之间的关系。
    • 若要设置层的自动调整大小规则,必须为该层的autoresizingMask属性指定适当的常量默认情况下,图层配置为具有固定的宽度和高度。在布局过程中,层的精确大小和位置是由核心动画自动计算出来的,涉及到基于许多因素的复杂计算集。核心动画在要求代理执行任何手动布局更新之前应用自动调整大小的行为,因此可以根据需要使用代理调整自动调整布局的结果。
  • 子层和剪切

    • 与视图不同,超层不会自动剪切位于其边界矩形之外的子层的内容。相反,在默认情况下,超层允许其子层整体显示。但是,可以通过将图层的masksToBounds特性设置为“是”来重新启用剪裁。
    • 层的剪切遮罩的形状包括层的角半径(如果指定了一个)。图4-3显示了一个图层,该图层演示了masksToBounds属性如何影响圆角图层。当该特性设置为“否”时,子图层将全部显示,即使它们超出了其父图层的边界。将属性更改为“是”会导致其内容被剪裁。
  • 转换图层之间的坐标值

    • 有时,您可能需要将一个图层中的坐标值转换为另一个图层中同一屏幕位置的坐标值。CALayer类提供了一组可用于此目的的简单转换例程:

    • 除了转换点和矩形值之外,还可以使用co在层之间转换时间值convertTime:fromLayer:和convertTime:toLayer:方法。每个层定义自己的本地时间空间,并使用该时间空间将动画的开始和结束与系统的其余部分同步。默认情况下,这些时间空间是同步的;但是,如果更改一组层的动画速度,则这些层的时间空间将相应地更改。可以使用时间转换方法来考虑任何此类因素,并确保两个层的计时同步。

高级动画技巧

  • 有许多方法可以配置基于属性的动画或关键帧动画,以便为您做更多的事情。
    • 需要同时或按顺序执行多个动画的应用程序可以使用更高级的行为来同步这些动画的计时将它们链接在一起。也可以使用其他类型的动画对象来创建视觉过渡和其他有趣的动画效果
  • 过渡动画支持对层可见性的更改
    • 顾名思义,过渡动画对象为层创建动画视觉过渡。过渡对象最常用的用法是以协调的方式设置一个层的外观和另一个层的消失的动画。与基于属性的动画不同,其中动画更改层的一个属性,变换动画操纵层的缓存图像以创建视觉效果,这些效果很难或不可能通过单独更改属性来实现。标准类型的变换允许您执行显示、推送、移动或交叉淡入动画。在OSX上,您还可以使用核心图像过滤器来创建使用其他类型的效果(如擦拭、页面卷曲、涟漪或您设计的自定义效果)的过渡。
    • 若要执行变换动画,请创建一个CATTransition对象并将其添加到变换涉及的层。指定过渡的开始点和结束点。也不需要使用整个变换动画。使用“过渡”对象,可以指定要在设置动画时使用的“开始”和“结束”进度值。这些值允许您执行诸如在动画中点开始或结束动画之类的操作。
    • 清单5-1显示了用于在两个视图之间创建动画推送转换的代码。在本例中,myView1和myView2位于同一父视图中的同一位置,但当前只有myView1可见。在myView1中,幻灯片从“myView1”变为“hidden”,并在“myView1”中从“幻灯片1”变为“hidden”,直到幻灯片从“myView1”变为“hidden”。更新两个视图的hidden属性可确保动画结束时两个视图的可见性都是正确的。
    • 当两个过渡层都涉及到同一个对象时,可以使用两个过渡层。使用相同的转换对象还可以简化必须编写的代码。但是,可以使用不同的过渡对象,如果每个层的变换参数不同,则肯定需要这样做。
    • 清单5-2展示了如何使用核心映像过滤器在OSX上实现转换效果。之后,应用动画的过程与其他类型的动画对象的过程相同。
    • 动画中使用核心图像过滤器时,最棘手的部分是配置过滤器。例如,对于条形滑动变换,指定过高或过低的输入角度可能会使其看起来好像没有发生任何转换。如果没有看到预期的动画,请尝试将过滤器参数调整为不同的值,以查看这是否会更改结果。
  • 自定义动画的计时:

    • 计时是动画的一个重要部分,对于核心动画,您可以通过CAMediaTiming协议的方法和属性为动画指定精确的计时信息。两个核心动画类采用该协议。CAAnimation类采用它,以便您可以在动画对象中指定计时信息。CALayer也采用它,这样您就可以为隐式动画配置一些与计时相关的特性,尽管包装这些动画的隐式事务对象通常提供优先的默认计时信息。
    • 当考虑计时和动画时,了解层对象如何与时间一起工作很重要。每个层都有自己的本地时间,用于管理动画计时。通常,两个不同层的本地时间非常接近,可以为每个层指定相同的时间值,用户可能不会注意到任何东西。但是,层的本地时间可以由其父层或其自己的定时参数修改。例如,更改层的“速度”特性会导致该层(及其子层)上动画的持续时间按比例更改。
    • 为了帮助您确保时间值适合给定层,CALayer类定义了convertTime:fromLayer:和convertTime:toLayer:方法。可以使用这些方法将固定时间值转换为图层的本地时间,或将时间值从一个图层转换到另一个图层。这些方法将考虑可能影响层的本地时间的媒体计时属性,并返回一个可用于其他层的值。清单5-3显示了一个示例,您应该定期使用它来获取某个层的当前本地时间。CACurrentMediaTime函数是一个方便的函数,它返回计算机的当前时钟时间,该方法将其转换为层的本地时间
    • 在层的本地时间中具有时间值后,可以使用该值更新动画对象或层的计时相关属性。使用这些计时属性,可以实现一些有趣的动画行为,包括:
    • 使用beginTime属性设置动画的开始时间。通常,动画在下一个更新周期中开始。可以使用beginTime参数将动画开始时间延迟几秒。将两个动画链接在一起的方法是设置一个动画的开始时间以匹配另一个动画的结束时间。
    • 如果延迟动画的开始,可能还需要将fillMode属性设置为kCAFillModeBackwards。此填充模式使层显示动画的开始值,即使层树中的层对象包含不同的值。如果没有此填充模式,将看到在动画开始执行之前跳转到最终值。其他填充模式也可用。
    • autoreverses属性使动画在指定的持续时间内执行,然后返回到动画的起始值。可以将此属性与repeatCount属性结合起来,在起始值和结束值之间来回设置动画。将自动反转动画的“重复计数”设置为整数(例如1.0)会导致动画在其起始值处停止。添加额外的半步(例如重复计数为1.5)会导致动画在其结束值处停止。
    • timeOffset属性与组动画一起使用,可以在比其他动画更晚的时间启动某些动画
  • 暂停和恢复动画:

  • 显式事务允许您更改动画参数:

    • 对层所做的每个更改都必须是事务的一部分。CATransaction类管理动画的创建和分组以及它们在适当的时间执行。在大多数情况下,您不需要创建自己的事务。每当您将显式或隐式动画添加到其中一个层时,Core Animation会自动创建隐式事务。但是,您也可以更精确地管理这些事务。
    • 使用CATransaction类的方法创建和管理事务。要启动(并隐式创建)新事务,请调用begin类方法;要结束该事务,请调用commit类方法。在这些调用之间是您希望成为事务一部分的更改。例如,你可以用清单5中的两个属性来改变代码。
    • 使用事务的主要原因之一是,在显式事务的范围内,可以更改持续时间、计时函数和其他参数。您还可以为整个事务分配一个完成块,以便在动画组完成时通知您的应用程序。更改动画参数需要使用设定值:forKey:方法。例如,要将默认持续时间更改为10秒,可以更改kCATransactionAnimationDuration键,如清单5-6所示。
    • 在需要为不同动画集提供不同默认值的情况下,可以嵌套事务。要将一个事务嵌套在另一个事务中,只需再次调用begin类方法。每个begin调用都必须与对commit方法的相应调用相匹配。只有在提交最外层事务的更改后,核心动画才会开始关联的动画。

    • 清单5-7显示了一个嵌套在另一个事务中的例子。在本例中,内部事务更改了与外部事务相同的动画参数,但使用了不同的值。
      - 向动画添加透视:
      Apps可以在三维空间中操纵层但为了简单起见,核心动画使用平行投影显示层,这基本上将场景展平为二维平面。此默认行为会导致具有不同zPosition值的大小相同的层显示为相同的大小,即使它们在z轴上相距很远。你通常在三维空间观察这样一个场景的透视图已经不见了。但是,您可以通过修改层的转换矩阵来包含透视信息来更改这种行为。

  • 修改场景的透视图时,需要修改包含正在查看的层的超层的子层变换矩阵。通过对所有子层应用相同的透视信息,修改超层可以简化必须编写的代码。它还可以确保透视图正确应用于在不同平面上彼此重叠的同级子层。
    清单5-8展示了为父层创建一个简单透视变换的方法。在这种情况下,customeyeposition变量指定沿z轴查看层的相对距离。通常为eyePosition指定一个正值,以保持层以预期的方式定向。值越大,场景越平坦,而值越小,层之间的视觉差异就越大

图层样式特性动画

  • 在渲染过程中,核心动画采用层的不同属性并按特定顺序渲染它们。此顺序决定层的最终外观。本章说明了通过设置不同的层样式属性所获得的渲染结果。
  • Geometry Properties(几何属性)
    • 图层的几何图形特性指定其相对于其父图层的显示方式。几何体还指定用于圆化层角点和变换的半径
  • 背景属性:
    • 核心动画渲染的第一件事就是图层的背景。可以为背景指定颜色。在OSX中,还可以指定要应用于背景内容的核心图像过滤器。图A-2显示了一个样本层的两个版本。左边的层设置了backgroundColor属性,而右边的层没有背景色,但是有一个边界,一些内容和一个收缩失真过滤器被分配给它的backgroundFilters属性。
      • backgroundFilters,iOS不支持
  • 图层内容: 如果图层有任何内容,则该内容将在背景色的顶部渲染。您可以通过直接设置位图、使用委托指定内容或通过子类化层并直接绘制内容来提供层内容。您可以使用许多不同的绘图技术(包括Quartz、Metal、OpenGL和Quartz Composer)来提供这些内容。图A-3显示了一个示例层,其内容是直接设置的位图。位图内容由一个很大程度上透明的空间组成,在右下角有一个自动机图标。
  • 子层内容
    • sublayers
    • masksToBounds
    • sublayerTransform
  • 边界属性:

    • 边框属性图层可以使用指定的颜色和宽度显示可选的边框。边界跟随层的边界矩形,并考虑任何角半径值。图A-5显示了应用边框后的示例层。请注意,位于层边界之外的内容和子层在边界下面呈现。
  • 过滤器属性: 在OSX中,可以将一个或多个过滤器应用于层的内容,并使用自定义合成过滤器来指定层的内容如何与其底层的内容混合。图A-6显示了应用核心图像后处理过滤器的样本层。

  • 阴影属性: 层可以显示阴影效果并配置其形状、不透明度、颜色、偏移和模糊半径。如果不指定自定义阴影形状,则阴影基于层中非完全透明的部分。图A-7显示了应用红色阴影的同一样本层的几个不同版本。左侧和中间版本包含背景色,因此阴影仅出现在层的边界周围。但是,右侧的版本不包括背景色。在这种情况下,阴影将应用于层的内容、边界和子层。

  • 不透明度特性

    • 图层的不透明度特性决定了在图层中显示多少背景内容。图A-8显示了不透明度设置为0.5的采样层。这允许部分背景图像通过 - 遮罩属性: 可以使用遮罩遮住层的全部或部分内容。遮罩本身是一个层对象,其alpha通道用于确定什么被阻止,什么被传输。遮罩层内容的不透明部分允许底层内容显示,而透明部分部分或完全遮住底层内容。图A-9显示了一个由遮罩层和两个不同背景组成的样本层。在左侧版本中,层的不透明度设置为1.0。在正确的版本中,图层的不透明度设置为0.5,这会增加通过图层遮罩部分传输的背景内容量。

CoreAnimation类图

posted @ 2020-11-10 01:49  阿甘左  阅读(239)  评论(0编辑  收藏  举报