Core Animation 系统学习第一篇

Core Animation 位于 AppKit 和 UIKit的底层,并被紧密的集成到视图工作流中。

Core Animation 本身并不是绘图系统,它是一个合成与操作您app内容于硬件中的基础框架。而在该框架中最为核心的便是 layer objects (层对象),用来管理和操作您的内容。一个layer 捕捉您的内容到位图中,这样有利于被视图硬件便捷地处理。在大部分app中,layers被用来管理视图内容但是你也可以根据你的需求创建单独的layers。

layer 的更改触发动画:你利用Core Animation 创建的大部分动画都包含layer的属性更改。

layers 可被组织成层级结构:layers 可以被层级结构化地组织创建父子关系。

Core Animation 并不是应用内view的替代品,它只是用来整合views以提供更为优秀的展示以及对内容的动画。它通过缓存views的内容到位图中以便可以被图形硬件直接的操作来达到上诉目标。在某些特定的情况下你也许需要知道怎样来展示以及管理应用的内容,但是在使用Core Animation的大多数时候你都不用考虑这些事情。除了缓存views 内容,Core Animation也定义了一个途径来指定任意视觉内容,将该内容与你的views整合,然后将其与其他对象一块动画。

在使用Core Animation的时候你通常不会像卡通片那样以每秒60帧的频率来更换view内容。

layers支持绘图与动画的基础能力

layer 对象是在3D空间中以2D表面被组织,而且在使用Core Animation 期间是任何处理的核心。与views相似的是,layers 管理它们表面的几何图形,内容,和视觉属性信息。而与views不同的是,layers不能定义它们自己的外观。一个layer对象很少去管理围绕一个位图的状态信息。位图本身是一个view绘制自己的结果或者是一个你指定的已调整过的image。基于此,你的应用中使用到的主要的layers应该被看作是一个model对象,因为它们主要管理数据。这个论点很重要要记下来,因为它影响了动画的行为。

layer-based drawing model

大多数层在应用程序中不做任何实际的绘图。相反,一个层捕获您的应用程序提供的内容,并在位图中缓存它,有时称为后备存储。当你随后改变了layer 的一个属性,就是改变了与layer对象相关的状态信息。当一个改变出发了动画,Core Animation会将该layer 的位图和状态信息传给绘图硬件,绘图硬件会将新信息渲染到位图中。在硬件中国呢处理位图生成动画比利用软件实现相同效果快的多。

由于它是操作一个静态位图,所以layer-based 绘制与更加传统的view-based绘制工艺大不相同。view-baesd绘制用drawRect方法和新的参数来重新绘制改变自身。但是由于view-based绘制是在CPU的主线程绘制的所以代价十分昂贵。而Core Animation 利用在硬件上操作缓存位图成功避免了这种消耗,而且还实现了相同或相似的效果。

虽然Core Animation里尽可能多用缓存内容,但是你的应用也应该提供初始内容并实时更新。

layer-based animations

一个layer 对象的数据和状态信息被从layer屏幕内容的视觉展示上分离出来。这种分离使Core Animation将它们插入并且将老状态值改变到新状态值动态改变。

在动画期间,Core Animation替你在硬件上逐帧绘制。你所需做的就是确定动画的开始与结束值,并且让Core Animation做剩余的工作。

layer对象定义它们自己的图形结构

layer与view 一致具有frame 和bounds 属性,但是layer还具有view 不具有的属性,例如anchor point

layers 用两种类型坐标系

层利用基于点的坐标系和单元坐标系来指定内容的位置。在基于点坐标系中更多使用bounds和position 属性而不是frame属性。position 属性定义的是layer的中间点,position是那些依据layer的anchorPoint 变的属性之一。anchorPoint代表了某些确定坐标系的起始点。anchorPoint是少数的几个需要用单位坐标系来确定的属性。Core Animation用单位坐标系来代表那些跟随layer的size改变而改变的属性。你也可以认为单位坐标系就是一个总的比例展示(0.0~1.0)。

anchor points 影响几何转换

anchor points 的影响在操作layer 的position 或者transform属性的时候尤为明显。position属性经常随着anchor point 属性确定。

layers 可以在三个维度上操作

每个layer 都有两个转换矩阵来操作该layer 和它的内容。calayer 的transform属性用于layer 和它的sublayer。一般来说,你用该属性来修改该layer自身。sublayerTransform属性只针对sublayers而且一般用于给一个场景添加透明视觉效果。

矩阵用法

layer trees 反映动画状态的不同方面

应用在使用Core Animation 时有三个layer 对象树集合,分别是model layer tree(或则简称 layer tree),presentation tree ,render tree .

  • model layer tree 中保存的对象是你的应用最常交互的。保存了动画的目标值。无论何时你改变一个layer 的属性,你都会用到其中一个对象。

  • presentation tree包含正在执行的动画的在使用中的值。那些值其实就是每时每刻在改变的那些值。

  • render tree 真正执行动画,是私有方法。

*可以利用presentation tree 来获取动画中的某个值,必须是还未结束的动画。

创建layer 对象

当有更好的layer 来替代原有view 的默认layer时,可以通过+(class)layerClass方法来修改。

  • 当view 使用Metal 或者OpenGL ES 来绘制内容时,可使用CAMetalLayer 或者CAEAGLLayer对象。

  • 有更好的表现效果的特殊layer 类

  • 你想利用Core Animation 的特殊的layer 类,例如,粒子发射器(particle emitters )或复制器(replicators)。

CALayer 子类的用处
  • CAEmitterLayer:
    Used to implement a Core Animation–based particle emitter system. The emitter layer object controls the generation of the particles and their origin.

  • CAGradientLayer:
    Used to draw a color gradient that fills the shape of the layer (within the bounds of any rounded corners).

  • CAMetalLayer:
    Used to set up and vend drawable textures for rendering layer content using Metal.

  • CAEAGLLayer/CAOpenGLLayer:
    Used to set up the backing store and context for rendering layer content using OpenGL ES (iOS) or OpenGL (OS X).

  • CAReplicatorLayer:
    Used when you want to make copies of one or more sublayers automatically. The replicator makes the copies for you and uses the properties you specify to alter the appearance or attributes of the copies.

  • CAScrollLayer:
    Used to manage a large scrollable area composed of multiple sublayers.

  • CAShapeLayer:
    Used to draw a cubic Bezier spline. Shape layers are advantageous for drawing path-based shapes because they always result in a crisp path, as opposed to a path you draw into a layer’s backing store, which would not look as good when scaled. However, the crisp results do involve rendering the shape on the main thread and caching the results.

  • CATextLayer:
    Used to render a plain or attributed string of text.

  • CATiledLayer:
    Used to manage a large image that can be divided into smaller tiles and rendered individually with support for zooming in and out of the content.

  • CATransformLayer:
    Used to render a true 3D layer hierarchy, rather than the flattened layer hierarchy implemented by other layer classes.

  • QCCompositionLayer:
    Used to render a Quartz Composer composition. (OS X only)

给layer 提供内容

一个layer的内容包含了一个你想展示的视觉效果数据的位图。你可以通过以下三种方式来给位图提供内容。

  • 直接给layer 对象的contents属性提供图像对象。(该技术最好用于layer内容很少或根本不改变的情况)

  • 给layer 设置委托对象,让委托对象绘制layer的内容。(该技术最好用于layer 内容定期改变而且可以被外部对象提供支持,如一个view)

  • 定义一个layer 的子类,重写它的绘制方法去提供layer内容。(该技术适用于你必须创建自定义layer的子类或者你想改变该layer的基础绘制方法)

*只有当该layer是由你自己创建时才有必要去考虑去给layer提供内容。

利用一个图像给layer 的content

给layer 的contents 属性赋值。该layer直接用图像对象而不会尝试去拷贝该图像,这样可以节省内存。你赋值给一个layer的image必须是CGImageRef类型。

利用委托来提供layer的content
  • 如果你的委托对象实现了displayLayer:方法,该方法会创建一个位图,并将该位图直接赋值给该layer的contents属性。

  • 如果你的委托对象实现了drawLayer: inContext: 方法,Core Animation 会创建一个位图,创建一个图形context去绘制位图,然后调用你的委托方法去填充该位图。

委托对象必须实现上述两个方法的一个,如果两个都实现了的话,只会执行displayLayer:方法。

当你的应用更倾向于加载或者创建它想展示的位图时,重写displayLayer:方法更为合适。eg:

- (void)displayLayer:(CALayer *)theLayer {
// Check the value of some state property
 if (self.displayYesImage) {
    // Display the Yes image
    theLayer.contents = [someHelperObject loadStateYesImage];
 }
 else {
    // Display the No image
    theLayer.contents = [someHelperObject loadStateNoImage];
 }
}

如果你没有预先渲染的images或则没有一个帮助对象去创建位图,你的委托可以利用drawLayer:inContext:方法来自动绘制内容。eg:

- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext {
CGMutablePathRef thePath = CGPathCreateMutable();

CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
CGPathAddCurveToPoint(thePath,
                      NULL,
                      15.f,250.0f,
                      295.0f,250.0f,
                      295.0f,15.0f);

CGContextBeginPath(theContext);
CGContextAddPath(theContext, thePath);

CGContextSetLineWidth(theContext, 5);
CGContextStrokePath(theContext);

// Release the path
CFRelease(thePath);
}

针对layer-backed的views应该通过重写view的方法去绘制。因为layer-backed的view会自动将自己设为自己layer的委托,并且实现所需的委托的方法,所以你也不必再去改变这些设置了。相反,你应该去实现view的drawRect:方法去绘制内容。

通过子类化去提供layer 的content

如果你在实现一个自定义layer类你可以重写你的layer class的绘制方法去实现绘制。但是layer自身去省城自定义内容并不常见,layer更为常见的是管理内容的展示。例如,CATiledLayer 类可以管理一个大image 通过将其分为可以单独管理和渲染的小tiles。因为只有该layer 拥有哪个tiles应该在被给定的时间被渲染的信息,他可以直接管理绘制行为。

当子类化时,你可以用以下两种方法来绘制layer的内容:

  • 重写layer的display方法,利用该方法去直接设置该layer 的contents属性。

  • 重写layer的drawInContext:方法,利用该方法在提供的图形context中绘制。

display方法是更新layer内容的主要入口,重写该方法可完全控制处理进程。但是重写该方法也意味着你需要负责去创建CGImageRef赋值给contents属性。如果你仅仅是想要绘制content,或者让你的layer管理绘制操作,你可以重写drawInContext:方法,让该layer创建后备存储。

tweaking the content you provide

对于image适配当前bounds的方式是由contentsGravity属性决定的。两种方式:一种是基于位置的适配,一种是基于scaling-based的方式

  • kCAGravityTopLeft,kCAGravityTop,kCAGravityTopRight,kCAGravityLeft,kCAGravityCenter,kCAGravityRight,kCAGravityBottomLeft,kCAGravityBottom,kCAGravityBottomRight.

  • kCAGravityResizeAspect:(按比例展示,可能会不全部填充),kCAGravityResize(全部填充,不按比例),kCAGravityResizeAspect(按比例全部填充,可能会部分超出)

高分辨率图像处理

layers 并没有设备的分辨率方面的信息。layer 仅仅是存储了一个指向位图的指针,然后以最好的方式来展示它并尽可能给出一个可用的像素。如果你用一个image 给一个layer 的contents赋值,你必须通过给该layer 的contentsScale属性赋值来给Core Animation 指定该image的分辨率。默认值为1.0,这是标准分辨率屏幕上的适合的值。如果要在retina屏幕上展示,将该值设置为2.0。

只有当你直接给layer 指定位图时才有必要改变contentsScale的值。一个在UIKit 和AppKit 种的layer-backed view会自动设置合适的scale 属性的。

调整一个layer 的视觉风格和外观

背景颜色在layer 的contents image 之下,而border 在该image之上。设置layer 的背景颜色、边界宽度/颜色等都是动画化的。当layer 的corner radius 非零时不可将layer设置为不透明。

layer支持corner radius

由于包含应用了透明掩膜,corner radius 不会对layer 的contents属性对应的image起作用除非masksToBounds属性被赋值YES。然而,corner radius 总会影响该layer的背景颜色及边界是如何被绘制的。

layer支持内置阴影

通过图层,相对于层的内容、不透明度和形状的布局可以控制阴影的颜色、位置。layer shadows 的opacity值默认为0,即完全透明。改变该值为非零值会使Core Animation 去绘制该阴影。谨记,设置阴影的位置时ios 与os x 坐标系是不一样的。

当向layer 添加阴影时,阴影就成为了layer content 的一部分,而且实际上会超出layer的矩阵尺寸。所以当你肯定了layer的maskToBounds属性时,阴影效果沿着边界被切除。因此,如果你想既要阴影效果又要使用边界掩盖,那么就要用两个layer来实现了。

PS:本文是根据官方文档翻译的,因为水平有限以及个人侧重点不同,肯定有些不足之处,本篇文章就权当作是自己的随笔记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值