如果 CALayer 边界如何独立地 CALayer 图像缩放

Posted

技术标签:

【中文标题】如果 CALayer 边界如何独立地 CALayer 图像缩放【英文标题】:Howto CALayer's image scale independently of CALayer's bounds 【发布时间】:2012-02-11 22:18:34 【问题描述】:

我找不到这个问题的答案。

我想知道如何使 calayer 中的图像大小小于 calayer 的边界大小。

我在 iPad 游戏中有几个棋子,每个棋子都是 CALayer,我让它们简单地使用 contentsGravity=kCAGravityResizeAspect 调整大小。图像在 30x30 的 CALayer 内为 128x128,因此图像会自动调整为 30x30,并且由于两者都是一个盒子,因此可以保持纵横比并正常工作。

在这里,我将 CALayer 的边界设置为与 superview 的大小成比例,因此 Pawn 始终呈现与视图相同的相对大小。这个在我的 calayer 的 sprite 类子类中:

-(void) setSpriteScaleToDice 
    CGFloat newSize = [self superlayer].bounds.size.width * 0.066666667f; 
    self.bounds=CGRectMake(0.0f, 0.0f, newSize, newSize);
    self.contentsGravity = kCAGravityResizeAspect; 

请注意,在我的情况下,CALayer 边界的最大值为 30x30,这对于触摸来说很小。这就是我面临的问题,由于体积小,很难“触摸”它们,有时触摸失败......

我正在考虑的一个想法是增加 calayer 的“边界”,同时保持图像的原始大小。问题是我搜索了很多,并尝试了 contentGravity、contentsCenter、contentsScale 等几个选项......但没有成功。

特别是,根据苹果文档看起来要走的路是使用 contentsCenter(而不是使用 contentsGravity),但是我在位图中得到了变形......

请,任何想法都非常欢迎,并提前感谢,

路易斯

【问题讨论】:

您是否尝试过使 CGImage 小于图层的边界并使用 kCAGravityResizeAspect? 感谢您的回答,我已经尝试过了,问题是“有时”我需要将边界增加到 128x128,并且来自一个小的原始 cgimage 会降低很多分辨率。 【参考方案1】:

这可能是一个愚蠢的问题,但你为什么使用CALayers 而不是UIViewsUIImageView 有一个 contentMode 属性,可让您轻松完成此操作(更不用说更容易用于触摸事件处理)。

也就是说,CALayer 有一个 contentsRect 属性,它似乎可以让您定义一个子矩形,以便在其中绘制内容,这样您就可以为所欲为。

另一种选择是将您的图像层放在一个更大的层中,并将其用于命中测试。

【讨论】:

感谢您的回答,我终于决定采用 CALayer 方式,它非常适合处理精灵和纹理图集(可能也是 uiviews),同时我也在为可可和可可触摸,所以我就这样走了。你的第二个选项(contentsRect)不能使用它,因为我正在做纹理图集。而且你的第三个推荐很有趣……我明天试试,然后回来。谢谢。 嗨。我终于选择将我的图像层放在一个更大的层中,并使用两个层来获得最热。现在它按预期工作。非常感谢。【参考方案2】:

CAlayer CGFloat contentsScale

/* Defines the scale factor applied to the contents of the layer. If
 * the physical size of the contents is '(w, h)' then the logical size
 * (i.e. for contentsGravity calculations) is defined as '(w /
 * contentsScale, h / contentsScale)'. Applies to both images provided
 * explicitly and content provided via -drawInContext: (i.e. if
 * contentsScale is two -drawInContext: will draw into a buffer twice
 * as large as the layer bounds). Defaults to one. Animatable. */

【讨论】:

【参考方案3】:

如果您希望在 CALayer 中以不同于 CALayer 的大小绘制图像,则需要创建自己的 drawInContext: 方法并绘制图像,而不是设置 CALayer 的 contents 属性。不要设置contents属性,创建自己的来跟踪你要绘制的图像。

【讨论】:

好的,谢谢推荐。我将首先测试尼克的选项,然后尝试这个。再次感谢。 我认为覆盖 drawInContext 会很慢 - 它使用核心图形而不是 OpenGL 进行绘图,因此它不是硬件加速的。 @NickLockwood 系统仅使用 OpenGL(或 Metal)进行合成(总是在合成 CALayers 和 CoreImage 图像时,但也用于 CoreGraphics 的许多合成操作) - 它从不使用 OpenGL 进行任何绘图操作(无论什么框架,不管什么系统)。如果您将位图图像绘制到位图绘图上下文中,那实际上是当今的合成而不是绘图,并且可以由 GPU 轻松完成。绘图是指绘制文本、线条、矩形、椭圆形或渐变色。 @NickLockwood 在有人抱怨之前,是的,Apple 已经编写了 QuartzGL,它实际上可以在 GPU 上执行“真正的绘图操作”。自 10.4 以来它是系统的一部分,但它从未默认启用(您可以使用 Apple 的 CoreGraphics 调试工具启用它);据说它有问题(产生视觉故障),因此所有绘图仍然由 CPU 完成。我不知道苹果是否也将那部分移植到了 ios,我对此表示怀疑。如果你暂时忽略文本渲染,那么今天 90% 的 UI 无论如何都不是绘制的而是合成的。 @Mecki 我认为这与我所说的并不矛盾(即使用图层内容属性缩放/裁剪图像将是硬件加速的,但通过使用核心图形绘制它们来手动裁剪它们在drawInContext里面:不会)

以上是关于如果 CALayer 边界如何独立地 CALayer 图像缩放的主要内容,如果未能解决你的问题,请参考以下文章

UIView和CALayer的关系及 iOS中的事件的产生和传递

CALayer subLayer 边界舍入错误?

在 NSView 边界更改中托管的 CALayer

Swift - 设置 CALayer 边界或框架不起作用

CALayer 不透明度动画有效,但边界动画无效

动画边界更改时具有 CALayer 有线效果的自定义视图