[译] Core Animation 编程指南 - 设置图层对象

本文首发地址html

图层对象是你用 Core Animation 所作的一切事情的核心。图层管理你 app 的视觉内容,提供视觉内容样式和视觉外观的修改选项。虽然 iOS app 内嵌自动支持图层,可是 OS X 上面的 app 开发者必须在利用图层的性能优点前手动让图层生效。一旦生效,你须要理解如何配置和操做你 app 的图层,来获取你想要的效果。git

让你的 App 支持 Core Animation

在 iOS 的 app 中, Core Animation 老是自动生效的,而且每一个视图是由图层支持的。在 OS X 中,app 必须经过下面的操做来使 Core Animation 生效:github

  • 与 QuartCore 框架连接(iOS app 只有在明确使用 Core Animation 的时候才必须与该框架连接)
  • 经过如下操做来使你的 NSView 对象支持图层:
    • 在你的 nib 文件,使用 View Effects 检查器来使你的视图支持图层。该检查器显示选中视图及子视图的复选框。推荐你尽量的将你的视图修改成图层支持的视图。
    • 若是你用代码建立的视图,调用视图的 setWantsLayer: 方法传递 YES 来讲明该视图应该使用图层。
  • 经过上面的任意一种方法均可以建立图层支持的视图。使用图层支持的视图,系统会管理建立底层的图层对象,保持图层的更新。在 OS X 上面,你也能够建立图层托管视图,由此,你的 app 实际会建立和管理底层的图层对象。(你不能在 iOS 上面建立图层托管视图)关于如何建立图层托管视图的更多信息,可参见 图层托管容许你改变 OS X 上的图层对象

改变视图关联的图层对象

图层支持的视图默认会建立 CALayer 的实例,多数状况下你不须要去改变图层对象的类型。但,Core Animation 提供了一些不一样的图层类,每个提供的图层类都是颇有用处的。选择不一样的图层类可能会提升你的代码性能,或者经过简单的方式支持一种指定的内容类型。例如, CATiledLayer 类经过高效的方式用来优化大型图片的显示。数组

改变视图使用的图层类

你能够经过重写视图的 layerClass 方法返回一个不一样的类对象,来改变 iOS 上视图使用的图层类。大多数的 iOS 视图建立一个 CALayer 对象,并使用该对象支持存储它的内容。对于你的大多数视图,默认的选择是不错的,你不须要去改变它。可是在某些状况下,你会发现一个不一样的图层类是更加合适的。例如,如下几种状况你可能想改变图层类:缓存

  • 你的视图使用 Metal 或者 OpenGL ES 来绘制内容,这种状况下,你应该使用 CAMetalLayer 或者 CAEAGLLayer 对象。
  • 有特定类型的图层对象能够提供更好的性能。
  • 你想使用一些特定的 Core Animation 图层类,例如粒子发射器(particle emitters)或复制器(replicators)。

改变视图的图层类是很是简单的;能够参见 例2-1 的例子。你须要作的就是重写 layerClass 方法,返回一个你想使用的类对象。显示以前,视图会调用 layerClass 方法,使用返回的类建立一个新的图层对象。视图的图层对象一旦被建立,就不可修改。bash

例 2-1 改变视图的图层类app

// OC
+ (Class) layerClass {
   return [CAMetalLayer class];
}

// Swift
override class var layerClass: AnyClass {
    return CAMetalLayer.self
}
复制代码

关于图层类的列表和你如何使用它们,可参见不一样的图层类提供专门的行为框架

改变 NSView 的图层类

你能够经过重写 NSView 对象的 makeBackingLayer 方法来改变它的默认图层类。在该方法里,建立、返回一个你想 AppKit 去用来支持你自定义视图的图层对象。你可能如下状况须要重写该方法:使用相似滚动图层(scrolling)或者平铺图层(tiled layer)的自定义图层。关于图层类的列表和你如何使用它们,可参见不一样的层类提供专门的行为ide

图层托管容许你改变 OS X 上的图层对象

图层托管视图:你本身建立、管理底层的图层的 NSView 对象。若是你想本身控制视图的图层类型,你须要使用图层托管。例如,你能够建立一个图层托管视图,这样你能够分配一个不一样的图层类,而不是默认的 CALayer 。你想使用一个单独的视图去管理独立图层的层级结构时,也能够建立图层托管视图。

当你的视图调用 setLayer: 方法而且提供了一个图层对象时,AppKit 将不会管理该图层对象。一般,AppKit 会更新视图的图层对象,但对于图层托管的视图,大多数属性不会更新。post

为了建立一个图层托管视图,你须要建立本身的图层对象,并在视图在屏幕显示以前将图层和视图关联起来,如例 2-2 中代码所示。为了设置图层对象,你必须调用 setWantsLayer: 方法让视图知道它应该使用图层。

例 2-2 建立一个图层托管视图

// Create myView...

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

// Add myView to a view hierarchy.
复制代码

若是你选择使用图层托管视图,你必须本身设置 contentsScale 属性,而且在合适的时机提供高分辨率的内容。关于高分辨率内容和倍率的更多内容,请参见使用高分辨率图像

不一样的图层类提供专门的行为

Core Animation 定义了不少标准图层类,这些类都是为某种特定的状况定义使用的。CALayer 是全部图层类对象的父类。它定义了全部图层对象必须支持的行为,且它是图层支持视图默认的图层类型。其它具体图层类可参见表 2-1。

2-1 CALayer 的子类和它们的使用

类名 具体用途
CAEmitterLayer 用于实现基于核心动画的粒子发射器系统。发射器层对象控制粒子的生成及其来源
CAGradientLayer 用于绘制填充图层形状的颜色渐变(在任何圆角的边界内)
CAMetalLayer 用于设置和提供可绘制纹理,以使用 Metal 渲染图层内容
CAEAGLLayer/CAOpenGLLayer 用于使用OpenGL ES (iOS) 或 OpenGL (OS X)设置渲染层内容的后备存储和上下文
CAReplicatorLayer 用于当你想自动拷贝一个或者多个子图层时。拷贝器会为你制做副本,而且使用你指定的属性值去修改副本的外观或属性
CAScrollLayer 用于管理一个由多个子图层组成的大的、可滑动的区域
CAShapeLayer 用于绘制立方形的贝斯曲线。 Shape layers 有利于绘制基于路径的形状,由于它们老是产生清晰的路径,而不是绘制到层的后备存储中的路径,后者在缩放时看起来不太好。然而,清晰的结果确实包括在主线程上渲染形状和缓存结果
CATextLayer 用于绘制文本或者富文本
CATiledLayer 用于管理大图像,该图像可分为较小的图块,并经过支持放大和缩小内容来单独呈现
CATransformLayer 用于渲染真正的3D图层层次,而不是由其余图层类实现的2D图层层次
QCCompositionLayer 用于渲染 Quartz Composer 结构(仅限 OS X)

提供图层的内容

图层是管理由你 app 提供的内容的数据对象。图层的内容由包含要显示的视觉数据的位图组成。你能够经过下面三种的任意一种方式来提供包含内容的位图:

  • 直接给图层对象的 contents 属性赋值一个 image 对象。(该方法适用于图层内容不改变或者不多改变的状况)
  • 给图层赋值一个委托对象(delegate object),让委托对象去绘制图层的内容。(该方法适用于图层内容周期性改变,而且能够由外部对象提供,例如视图。即 视图为图层的 delegate
  • 定义图层子类,经过重写它的绘制方法来本身提供图层内容。(若是你不得不建立自定义的图层类,或者你想改变图层的底层绘制行为,你应该用该方法)

你仅须要本身建立图层对象的时候去考虑为图层提供内容。若是你的 app 中都是图层支持的视图,你不须要担忧使用上面提到的方法。图层支持视图会用高效的方法自动提供关联图层的内容。

使用 Image 做为图层的内容

由于图层只是管理位图图像(bitmap image)的一个容器,你能够直接给图层的 contents 属性赋值 image 对象。给图层赋值一个 image 是很是容易的,而且容许你指定想显示在屏幕上确切的 image 。图层使用你直接提供的 image 对象,不会试图建立 image 的副本。当你在多个地方使用同一个 image 时,这种行为会节省你的内存。

你赋值给图层的 image 必须是 CGImageRef 类型(在 OS X v10.6 及之后,你也能够赋值 NSImage 对象)。当赋值 image 时,记住需提供与本机分辨率匹配的图像。对于 Retina 显示屏,可能须要你去调整 image 对象 contentsScale 属性的值。关于对图层使用高分辨率内容的更多信息,请参见使用高分辨率图像

使用 Delegate 给图层提供内容

若是图层内容动态改变,你能够在须要的时候使用 delegate 对象来提供、更新图层内容。在显示时间,图层会调用 delegate 的方法去提供的须要的内容:

  • 若是 delegate 实现了 displayLayer: 方法,该方法会建立位图并将它赋值给图层的 contents 属性。
  • 若是 delegate 实现了 drawLayer:inContext: 方法,Core Animation 会建立位图,而后建立一个图形上下文(graphics context)来绘制该位图,最后调用 delegate 方法填充位图。delegate 方法必须在绘制到提供的图形上下文中。

delegate 对象必须实现 displayLayer:drawLayer:inContext: 方法。若是 delegate 实现了这两个方法,图层只会调用 displayLayer: 方法。

当 app 去加载或者建立想显示的位图时,重写 displayLayer: 方法是很是适合的。例 2-3 简单展现了如何实现 displayLayer: 方法。在该例中,delegate 使用了 helper 对象去加载显示它须要的 image。delegate 基于它内部状态来选择显示哪一个 image,在该例中,内部状态是叫作 displayYesImage 的自定义属性。

例 2-3 直接设置图层内容

- (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];
    }
}
复制代码

若是你没有预渲染的 image 或者 helper 对象去建立位图,delegate 可使用 drawLayer:inContext: 方法动态绘制图层内容。例 2-4 展现了关于 drawLayer:inContext: 方法实现的简单例子。在该例中,delegate 使用固宽和当前渲染颜色绘制了一个简单的曲线路径。

例 2-4 绘制图层内容

- (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);
}
复制代码

对有自定义内容的图层支持视图,应该继续重写视图的方法来作绘制。图层支持视图自动将本身设置为关联图层的 delegate,而且实现了须要实现的方法,你不该改变配置。你应该实现 drawRect: 方法来绘制你的内容。

在 OS X v10.8及之后的版本,绘图的另外一个选择是:经过重写视图的 wantsUpdateLayerupdateLayer 方法提供位图。重写 wantsUpdateLayer 并返回 YES ,由于 NSView 类遵循备用渲染路径。代替调用 drawRect: ,视图调用 updateLayer 方法,该方法必须直接给图层 contents 属性赋值位图。在这种状况下,AppKit 但愿直接设置视图图层对象的内容。

经过子类提供图层内容

若是你实现了自定义图层类,你能够重写你图层类的绘制方法来作任何绘制。对图层对象来讲,生成自己自定义内容并不常见,但图层固然能够管理显示的内容。例如,CATiledLayer 类经过将大图像分割成若干小图像(所以能够独立管理和渲染它们)的方法来管理大图像。由于只有图层知道哪个小图像在给定的时间上被渲染,因此图层直接管理绘制行为。

当建立自定义子类时,能够经过下面的两种方法来绘制图层内容:

  • 重写图层的 display 方法,使用该方法直接给图层的 contents 属性赋值。
  • 重写图层的 drawInContext: 方法,使用该方法绘制到提供的图形上线文中。

重写哪个方法取决于你须要控制多少绘制过程。 display 方法是更新图层内容的主入口点,因此重写该方法能够完整的控制绘制过程。重写 display 方法也意味着你须要建立赋值给 contents 属性的 CGImageRef 类型的对象。若是你只是想绘制内容(或者让图层管理绘制操做)你能够重写 drawInContext: 方法,让图层建立备用存储(backing store)给你。

旋转你提供的内容

当你给图层的 contents 属性赋值图像时,图层的 contentsGravity 属性决定如何操做图像以配当前边界的。默认状况下,若是图像比当前边界更大或者更小,图层对象会将图像调整到有效空间内。若是图层边界的宽高比(aspect ratio)与图像的宽高比不一样,会形成图像的变形。你可使用 contentsGravity 属性确保内容获得了最好的展现。

能够赋给 contentsGravity 属性的值被分为两个类:

  • 基于位置的重力常数:容许你将图像固定到图层特定的边缘或角上,而无需缩放图像。
  • 基于缩放的重力常数:容许你使用选项去缩放图像,一些保持了宽高比,一些没有。

图 2-1 展现了基于位置的重力设置如何影响图像。除了 kCAGravityCenter 常量以外,每一个常量都将图像固定在图层边界矩形的特定边缘或角上。kCAGravityCenter 常量将图像置于图层中心。这些常数都不会使图像缩放,因此图像老是以原尺寸进行渲染。若是图像比图层的边界大,可能会形成图像的部份内容被裁减;若是图像比图层的边界小,图层未被图像覆盖的部分会填充图层的背景色(若是设置的话)。

图2-1 图层基于位置的重力常数

图 2-2 显示了基于缩放的重力常量如何影响你的图像。若是图像尺寸没有彻底和图层的尺寸一致的话,全部的常量都会缩放图像。它们直接的不一样就是如何影响图像的原始宽高比。一些会保持宽高比,一些则不会。默认状况下,图层的 contentsGravity 属性设置为 kCAGravityResize 常量,它是惟一一个不保持图片宽高比的常量。

图 2-2 图层基于缩放的重力常数

使用高分辨率的图像

图层对于设备屏幕的分辨率一无所知。图层只存储了位图的指针,用给定的可用像素尽量最好的方式显示它。若是你给图层的 contents 属性赋值了图像,你必须告诉 Core Animation 由图层 contentsScale 属性设定的合适的值来决定的图像分辨率。该属性默认值为 1.0 ,对于显示在标准分辨率屏幕上的图像来讲,它是一个合适的值。若是你的图像放在 Retina 屏上,应该把值设置为 2.0。

仅在你直接给图层赋值位图的时候修改 contentsScale 属性的值。UIKit 和 AppKit 里图层支持的视图会基于屏幕分辨率和视图管理的内容自动给图层的设置一个合适的比例值。例如,若是你给 OS X 的图层 contents 属性值赋值 NSImage 对象,APPKit 会观察图像是否包含标准和高分辨两个类型的图像。若是有,APPKit 会使用正确的图像以适配当前屏幕,也会给 contentsScale 属性设置适配当前屏幕的值。

在 OS X 里,基于位置的重力常数会影响从指定给图层的图像对象中选择图像表示的方式。由于这些常数不会致使图像缩放,因此 Core Animation 依赖于 contentsScale 属性来选择具备最合适像素密度的图像表示。

在 OS X 里,图层的 delegate 能够实现 layer:shouldInheritContentsScale:fromWindow: 方法,并使用该方法去改变比例值。不管什么时候给定 window 的分辨率改变,AppKit 都会自动调用该方法, 这是可能的,由于图像会在标准分辨率和高分辨率的屏幕上移动。若是 delegate 支持改变图层图像的分辨率,那实现方法应该返回 YES 。当须要去反应新的分辨率时,该方法应该及时更新图层的内容。

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

图层对象有内嵌的视觉装饰,例如你能够在图层的主内容上添加边界线和背景色。由于这些视觉装饰不要求你作任何的渲染,因此它们使得在某些状况下能够将图层用做独立实体。你所须要作的就是设置图层的属性值,涂岑会处理必要的绘制,包括任何动画。有关这些视觉装饰如何影响图层外观的其余说明,请参见图层样式属性动画

图层有它们本身的背景和边界线

图层能够在基于图像的内容上显示填充满的背景色和描绘边框。背景色在图像内容后面绘制,边界线会在图像的上方绘制,如图 2-3 所示。若是图层包含子图层,它们也会出如今边界线的下方。由于背景色位于图像的后面,因此它会透过任何图像透明的部分。

图 2-3 给图层添加背景和边界线

例 2-5 展现了设置图层背景色和边界线所需的代码。这些都是能够进行动画的。

例 2-5  设置图层的背景色和边界线
// OC
myLayer.backgroundColor = [NSColor greenColor].CGColor;
myLayer.borderColor = [NSColor blackColor].CGColor;
myLayer.borderWidth = 3.0;

//Swift 
myLayer.backgroundColor = NSColor.green.cgColor
myLayer.borderColor = NSColor.black.cgColorlor
myLayer.borderWidth = 3.0
复制代码

注意:对图层的背景色你可使用任意类型的颜色,包括有透明度的颜色或者使用图案图像。当使用图案图像(pattern image)时, 要注意到Core Graphics 会使用标准坐标系处理图案图像的渲染,这和 iOS 上默认的坐标系是不一样的。所以,除非你反转坐标,不然在 iOS 上渲染的图像默认会颠倒显示。

若是你给图层背景色设置了不透明颜色,考虑将图层的 opaque 属性设置为 YES 。这样作能够提升屏幕合成图层时的性能,并消除图层后台存储管理 alpha 通道的须要。可是,若是图层的角半径也非零,则不能将其标记为不透明。

图层支持设置角半径

你能够经过给图层添加一个角半径来实现矩形圆角的效果。角半径是视觉修饰,经过遮罩图层边界角的一部分来容许底层内容的显示,如图 2-4 显示。由于它涉及透明遮罩,因此角半径不会影响图层 contents 属性的 image,除非 masksToBounds 属性值为 YES 。但,角半径老是会影响图层的背景色和边线的绘制。

图 2-4 图层上的圆角
设置图层 cornerRadius 属性的值能够为图层设置角半径。你指定的半径值使用点为单位,而且在图层显示前会应用到图层的四个角。

图层支持内嵌阴影

CALayer 包含几个属性能够用来配置阴影效果。阴影经过使图层看起来像漂浮在底层内容之上来增长图层的深度。这是另外一个视觉装饰,在某些状况下这是很是有用的。经过图层,你能够控制阴影的颜色、相对于图层内容的位置、透明度和形状。

图层阴影的透明度的值默认为 0,这会有效的隐藏阴影。将透明度改为一个非零值,会使 Core Animation 绘制阴影。由于阴影默认的位置是在图层下面的,在你看到它以前,须要你改变阴影的偏移量。记住下面这一点是很重要的,你指定阴影的偏移量是使用图层原始坐标系来应用的,而 iOS 和 OS X 是不一样的。图 2-5 显示了在右下方有阴影的图层。在 iOS 上,y 轴的值应该是正数,而在 OS X 上面 y 轴的值应该为负数。

图 2-5 在图层上应用阴影

当在图层上添加阴影时,阴影是图层内容的一部分,但实际上它会延展到图层边界以外。所以,若是你将图层的 masksToBounds 属性设置为 YES ,边界以外阴影的效果也会被剪切掉。若是你的图层包含任何透明内容,会形成一个奇怪的效果:在图层下面阴影的部分仍然可见,可是在图层边界以外的是不可见的。若是你想同时使用阴影和边界蒙版,你应该用两个图层来代替。对包含你内容的图层应用蒙版,再将该图层嵌入到有阴影效果的彻底相同尺寸的图层中。

关于如何对图层应用阴影的例子,请参见阴影属性

给 OS X 视图添加过滤器视觉效果

在 OS X app 里,你能够直接对图层内容应用 Core Image 过滤器。你能够经过过滤器来使图层内容模糊或者锐化,去改变颜色、扭曲内容、执行不少其余类型的操做。例如,图像处理程序可能会使用过滤器无损的修改图像,视频编辑程序可能使用它们实现不一样类型的视频过渡效果。而且由于过滤器是用硬件应用在图层内容上的,因此渲染是很快且平滑的。

注意:你不能给 iOS 上的图层添加过滤器。

对于给定的图层,你能够对图层内容的前景和背景应用过滤器。前景内容由图层本身包含的全部内容组成,包含 contents 属性的图像、背景色、边界线和子图层的内容。背景内容是直接位于图层下方但实际上不是图层自己的一部分的内容。大多数图层的背景内容是它的直接父图层,其父图层可能整个或者部分被其遮罩。例如,当你想用户专一于图层前景内容时,会对图层背景应用模糊过滤器。

你能够经过下面的图层属性来添加 CIFilter 类型的指定过滤器:

  • filters 属性包含一个数组,数组元素为仅能影响图层前景的过滤器。
  • backgroundFilters 属性包含一个数组,数组元素为仅能影响图层背景的过滤器。
  • compositingFilter 属性定义了图层的前景和背景内容如何被组合在一块儿。

为了给图层添加过滤器,你必须定位、建立 CIFilter 对象,并在对象添加到图层以前将它配置好。 CIFilter 类包含几个用来定位可用 Core Image 过滤器的类方法,如 filterWithName: 。建立过滤器只是第一步,不少过滤器有定义过滤器如何修改图像的参数。例如,盒子模糊过滤器有一个输入半径的参数,该参数用于应用的过滤器的数量。做为过滤器配置过程的一部分,你应该始终提供这些参数的值。可是,一个不须要指定的常见参数是输入图像,它由图层自己提供。

当向图层添加过滤器时,最好在过滤器添加到图层以前配置过滤器的参数。主要缘由是:一旦将过滤器添加到图层上,你就不能 CIFilter 对象自己来修改它了。可是,在添加到图层以后,你可使用图层的 setValue:forKeyPath:方法来修改。

例 2-6 展现了如何建立收缩失真滤波器并将其应用到图层上。此滤镜向内收缩图层的源像素,最大程度地扭曲最靠近指定中心点的像素。注意在该例中你不须要指定过滤器的输入图像,由于图层的图像会被自动使用。

例 2-6 对图层应用过滤器

CIFilter* aFilter = [CIFilter filterWithName:@"CIPinchDistortion"];
[aFilter setValue:[NSNumber numberWithFloat:500.0] forKey:@"inputRadius"];
[aFilter setValue:[NSNumber numberWithFloat:1.25] forKey:@"inputScale"];
[aFilter setValue:[CIVector vectorWithX:250.0 Y:150.0] forKey:@"inputCenter"];
 
myLayer.filters = [NSArray arrayWithObject:aFilter];
复制代码

有关可用 Core Image 过滤器的信息,请参见Core Image Filter 参考

OS X 的视图图层重绘策略会影响性能

在 OS X 里,图层支持视图支持几个不一样的策略,用来决定什么时候更新底部图层的内容。由于原生 AppKit 绘制模型和由 Core Animation 介绍的方法是不一样的,这些策略使你将老代码迁移到 Core Animation 技术上变得更加简单。你能够逐个视图地配置这些策略,以确保每一个视图的最佳性能。

每一个视图都定义了 layerContentsRedrawPolicy 方法,用来返回是图图层的重绘策略。你可使用 setLayerContentsRedrawPolicy 方法来设置策略。为了保持与传统绘图模型的兼容性,AppKit 默认状况下会将重绘策略设置为 NSViewLayerContentsRedrawDuringViewResize。可是,你能够将策略改成表 2-2 的任意一个值。注意推荐的重绘策略并非默认的那个。

表 2-2 OS X 视图的图层重绘策略

策略 用法
NSViewLayerContentsRedrawOnSetNeedsDisplay 这是推荐的策略。用该策略,视图几何图形的改变不会自动形成视图去更新图层的内容。取而代之的是,拉伸和操纵图层的现有内容,以方便几何图形的更改。想强制视图重绘它自身,并更新图层的内容,你必须显示的调用图层的 setNeedsDisplay 方法。 该策略最接近于 Core Animation 图层的标准行为。可是,它不是默认策略,必须显式设置。
NSViewLayerContentsRedrawDuringViewResize 这是默认的重绘策略。该策略经过不管什么时候视图几何图形改变,都会从新缓存图层的内容的方法,与传统 AppKit 绘制保持了最大的兼容性。该行为会形成视图的 drawRect: 方法在从新设置尺寸期间在 app 主线程屡次调用。
NSViewLayerContentsRedrawBeforeViewResize 使用该策略,在任何调整尺寸的操做以前,AppKit 以最终尺寸绘制图层,并缓存该位图。调整尺寸操做使用缓存位图做为起始图像,缩放它以适应旧的边界矩形。而后,它将位图动画化为最终尺寸。这种行为会致使视图内容在动画开始时出现拉伸或扭曲,在初始外观不重要或不明显的状况下效果会更好。
NSViewLayerContentsRedrawNever 使用策略,即便调用 setNeedsDisplay: 方法,AppKit 也不会更新图层。此策略最适合内容从不改变的视图,以及视图大小不多改变(若是有的话)的视图。例如,你能够将它用于显示固定大小内容或背景元素的视图。

视图重绘策略减轻了使用独立子图层来提升绘图性能的须要。在引入视图重绘策略以前,有些图层支持视图比须要的绘制频率更高,从而致使性能问题。解决这些性能问题的方法是使用子图层来呈现视图内容中不须要按期重绘的部分。随着重绘策略在 OS X v10.6 中的引入,如今建议将图层层支持视图的重绘策略设置为适当的值,而不是建立显式子图层结构。

给图层添加自定义属性

CAAnimation 和 CALayer 类延伸了键值编码约定来支持自定义属性。你可使用该行为来给图层添加数据,而后使用你自定义的键来获取。你甚至能够给你的自定义属性关联事件,以致于当你改变属性时,能够执行响应的动画。

有关如何设置和获取自定义属性的信息,请参见符合键值编码的容器类。有关向图层对象添加动做的信息,请参见改变图层的默认行为

打印图层支持视图的内容

在打印过程当中,图层会根据须要从新绘制其内容,以适应打印环境。Core Animation 一般在渲染到屏幕上时依赖于缓存的位图,但在打印时会重绘该内容。特别是,若是一个图层支持视图使用 drawRect: 方法来提供图层内容,Core Animation 在打印过程当中再次调用 drawRect: 来生成打印的图层内容。

最后

相关文章
相关标签/搜索