31

文档中,Apple 声明您需要在以下情况下考虑图层的比例因子:

  • 创建具有不同比例因子的附加核心动画层,并将它们合成到自己的内容中
  • 直接设置核心动画层的内容属性

最后一个陈述对我来说并不完全清楚。他们还说:

直接使用 Core Animation 层来提供内容的应用程序可能需要调整其绘图代码以考虑比例因子。通常,当您在视图的 drawRect: 方法或图层代理的 drawLayer:inContext: 方法中进行绘制时,系统会自动调整图形上下文以考虑比例因子。

通常还是总是?这仅对视图的托管支持层或我作为子层添加到支持层的每一层有效?因为他们还说:

如果您的应用程序创建没有关联视图的图层,则每个新图层对象的比例因子最初设置为 1.0。如果您不更改该比例因子,并且随后在高分辨率屏幕上绘制图层,则图层的内容将自动缩放以补偿比例因子的差异。如果您不希望内容被缩放,您可以将图层的比例因子更改为 2.0,但如果您在不提供高分辨率内容的情况下这样做,则现有内容可能看起来比您预期的要小。要解决该问题,您需要为图层提供更高分辨率的内容。


我很难想象没有视图的图层,我可以想象图层的层次结构,但是一旦我想显示它们,我应该将其添加为视图支持层的子层次结构,或者确实存在使用它们的其他方法(比如在上下文中创建和渲染)?

Core Animation 的合成引擎会查看每个图层的 contentsScale 属性,以确定合成期间是否需要缩放该图层的内容。如果您的应用程序创建没有关联视图的图层,则每个新图层对象的比例因子最初设置为 1.0。如果您不更改该比例因子,并且随后在高分辨率屏幕上绘制图层,则图层的内容将自动缩放以补偿比例因子的差异。如果您不希望内容被缩放,您可以将图层的比例因子更改为 2.0,但如果您在不提供高分辨率内容的情况下这样做,则现有内容可能看起来比您预期的要小。要解决该问题,您需要为图层提供更高分辨率的内容。

这实际上是什么意思?当我做类似的事情时,layer.contents = (id)image.CGImage我需要设置 contentsScale。
当我的图层绘制调用委托方法的内容 drawLayer:inContext:并且该图层不是视图的支持层时,我是否还需要设置它?

4

3 回答 3

17

re: 图层内容通过 -drawRect: 或 -drawLayer:inContext:

通常还是总是?这仅对视图的托管支持层或我作为子层添加到支持层的每一层有效?

总是。当调用这些方法时,当前上下文已经应用了缩放因子。例如,如果您的图层为 10pt x 10pt,则它的边界为 {0,0,10,10},而与 contentsScale 无关。如果 contentsScale = 2(例如你在视网膜上),这实际上是 20x20 像素。CALayer 已经设置了一个 20x20px 的后备存储并应用了比例因子 CGContextScaleCTM(context, 2, 2)。

这样您就可以在 10x10 的概念空间中进行绘图,但如果像素加倍,则后备存储会加倍。

我很难想象没有视图的图层,我可以想象图层的层次结构,但是一旦我想显示它们,我应该将其添加为视图支持层的子层次结构,或者确实存在使用它们的其他方法(比如在上下文中创建和渲染)?

您可以创建它们,将它们添加为子图层,并将它们的委托设置为您实现 -drawLayer:inContext: 的对象,或者您可以直接设置图层的内容。在 iOS 上,UIView 是一个相当浅的 CALayer 包装器,因此创建子视图而不是直接创建子层通常是有意义的,这就是您不太熟悉这种用法的原因。在 OS X 上,支持层的 NSView 是一个大而复杂的 CALayer 包装器,因此在单个视图中创建整个层的层次结构更有意义。

这实际上是什么意思?当我执行类似 layer.contents = (id)image.CGImage 的操作时,我需要设置 contentsScale。

是的。但是文档中的这段话告诉你的是,如果你不想看起来丑陋,一个 contentScale 为 2 的 10pt x 10pt 层需要一个 20px x 20px 图像的内容。即直接设置图层内容时需要注意图层的contentsScale,避免缩放伪影。

当我的图层调用委托方法 drawLayer:inContext: 并且该图层不是视图的支持层时,我是否还需要设置它?

是的。如果您自己创建图层(不是通过 UIView 创建的),则需要手动设置它们的比例。通常这只是 layer.contentsScale = [[UIScreen mainScreen] scale]。(同样,在 OS X 上这有点复杂,因为屏幕可以在运行时来来去去。)

于 2013-12-22T03:32:43.907 回答
7

在 OS X 上,你基本上

  1. 抓住你的窗户-backingScaleFactor
  2. 将每个(!)图层-contentsScale设置为该 scaleFactor
  3. -layer:shouldInheritContentsScale:fromWindow:在控制器中实现
  4. 将每一层设置-delegate为该控制器

我知道在 SO 上仅引用外部 URL 是不受欢迎的,但很难描述这一点。以下是一些关于比例因子对我来说正确的代码:

https://github.com/JanX2/ScrollingAboutWindow

希望有帮助。

于 2013-12-16T08:13:38.017 回答
6

虽然图层几乎总是在视图中使用,但该图层可能已被临时创建并添加为视图图层的子图层,或指定为另一个图层的蒙版。在这两种情况下,contentsScale都必须设置属性。例如:

UIView *myMaskedView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
CALayer *myMaskLayer = [CALayer new];
myMaskLayer.frame = myMaskedView.bounds;
UIImage *maskImage = [UIImage imageNamed:@"some_image"];
myMaskLayer.contents = (id)maskImage.CGImage;
myMaskLayer.contentsScale = maskImage.scale;
myMaskedView.layer.mask = myMaskLayer;

您可能还想构建一个层次结构来执行动画,而不是使用每个层来支持一个视图:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];

CALayer *sublayerA = [CALayer new];
sublayerA.contentsScale = myView.layer.contentsScale;
[myView.layer addSublayer:sublayerA];

CALayer *sublayerB = [CALayer new];
sublayerB.contentsScale = myView.layer.contentsScale;
[myView.layer addSublayer:sublayerB];

// Continue adding layers   

这对于原生屏幕比例为 2.0 的 Retina 设备尤其重要;默认比例为 1.0 的图层会显示明显的像素化。

于 2013-12-18T19:04:17.353 回答