CATiledLayer 在绘制内容之前消隐图块

Posted

技术标签:

【中文标题】CATiledLayer 在绘制内容之前消隐图块【英文标题】:CATiledLayer blanking tiles before drawing contents 【发布时间】:2010-12-15 04:50:11 【问题描述】:

全部,

我无法从 CATiledLayer 获得我想要的行为。有没有一种方法可以触发瓷砖重绘,而不会产生首先将它们的区域清除为白色的副作用?我已经将 CATiledLayer 子类化为将 fadeDuration 设置为返回 0。

更具体地说,以下是我所看到的以及我正在努力实现的目标的详细信息:

我有一个内容尺寸很大的 UIScrollView...~12000x800。它的内容视图是一个由 CATiledLayer 支持的 UIView。 UIView 使用大量自定义绘制的线条呈现 一切正常,但 UIView 的内容有时会发生变化。发生这种情况时,我想尽可能无缝地重绘瓷砖。当我在视图上使用 setNeedsDisplay 时,图块会重新绘制,但它们首先会被清除为白色,并且在绘制新内容之前会有几分之一秒的延迟。我已经对 CATiledLayer 进行了子类化,以便将 fadeDuration 设置为 0。 我想要的行为似乎应该是可能的......当您放大滚动视图并以更高的分辨率重绘内容时,重绘之前没有空白;新内容绘制在旧内容之上。这就是我要找的。​​li>

谢谢;我很欣赏你的想法。

更新

只是跟进 - 我意识到在重绘之前瓷砖并没有被清除为白色,它们被完全取出;我看到的白色是我的 CATiledLayer 支持的视图下方的视图颜色。

作为快速破解/修复,我在 UIScrollView 下方放置了一个 UIImageView,在触发 CATiledLayer 支持的视图的重绘之前,我将其可见部分渲染到 UIImageView 中并让它显示。这大大平滑了重绘。

如果有人有更好的解决方案,比如在重绘之前保持重绘目标瓷砖不消失,我仍然很想听听。

【问题讨论】:

对不起。但是“在触发 CATiledLayer 支持的视图的重绘之前”是什么时候? drawLayer:inContext: ? 【参考方案1】:

我发现如果您将levelsOfDetailBias 和levelsOfDetail 都设置为相同的值(在我的例子中为2),那么它只会重绘我的setNeedsDisplayInRect: 调用所触及的图块,正如您所希望的那样。

但是,如果levelsOfDetail 与LODB 不同,则任何对setNeedsDisplayInRect 的调用:重绘所有 切片。

【讨论】:

没有。这不是哪些瓷砖需要重绘的问题。问题在于,如果需要重绘一个图块,则先将图块清除为白色,然后再绘制新内容。我们想要的是磁贴可以在新内容到达之前显示缩放的旧内容,但不仅仅是白色。 @Chris,这对我也有帮助,但你现在是这种行为的原因吗? @Azat 不幸的是,我作为 ios 开发人员遇到的(长)iOS 错误列表中的另一个:) 我在 Xcode 7.3.1 中看到了 setNeedsDisplayInRect() 的这个问题,但遗憾的是,即使设置匹配 4/4 或 2/2,它总是会重新渲染所有图块【参考方案2】:

您可以在现有的平铺图层后面添加另一个图层(可能是 CATiledLayer)。 (一种双缓冲解决方案。)您可以从几秒钟后触发的计时器调用第二层上的setNeedsDisplay:,以确保该层不会与前层同时重绘。

【讨论】:

如果 CAtiles 不可见(在某物后面或屏幕外),则它们不会绘制【参考方案3】:

另一个可能的选择是使用相同的委托将内容绘制到位图上下文中,并在内容刷新后将位图交换到后备存储中。这应该会产生无闪烁的结果。话虽如此,我无法告诉您这是如何完成的,而 CATiledLayers 的一个好处是它们会在您缩放时自动生成图块,并在您平移放大后预生成图块。

我想看看您如何实现您的应用程序。几周以来,我一直在寻找一个结合使用 UIScrollView 和 CATiledLayer-back 视图以及许多自定义绘制线条的示例。 Apple 有一些很棒的示例代码 - 但它们都涉及图像而不是线条艺术,所以对我没有帮助。

【讨论】:

【参考方案4】:

在没有解决方案的情况下通读这些答案后,我发现平铺页面是主要的后台任务。 在高优先级队列上准备我的 lo-res 占位符图像解决了这个问题 - 图像现在在平铺发生时出现。缓存占位符图像进一步改善了它们的外观 - 它们出现在平铺开始之前。 使用较新的设备,平铺速度如此之快,这些技巧可能无关紧要。由大型扫描图像(例如扫描的书)组成的 PDF 样本在我的经验中是最慢的,并且可以提供良好的测试数据。

【讨论】:

【参考方案5】:

我在 iPad 上遇到了同样的问题。

解决方案比我想象的要简单,也比在重绘前使用 UIImageView 渲染显示要简单得多...:

只是不要为图层设置任何背景颜色!

我以类似的方式设置了 CATiledLayer:

layer = [[CATiledLayer alloc] init];
layer.masksToBounds = YES;
layer.contentsGravity = kCAGravityLeft;

//layer.backgroundColor = [[UIColor whiteColor] CGColor];

layer.tileSize = CGSizeMake(1004.0, 1004.0);
layer.levelsOfDetail = 16;
layer.levelsOfDetailBias = 8;

请注意,我已将线条设置图层的背景颜色注释为白色。 之后,重绘问题之前的白色空白消失了!

如果有人尝试过,请告诉我。

【讨论】:

这对我不起作用,删除背景颜色对重新绘制之前的瓷砖消隐没有任何影响。

以上是关于CATiledLayer 在绘制内容之前消隐图块的主要内容,如果未能解决你的问题,请参考以下文章

CATiledLayer 显示以前的图块

CATiledLayer 的背景图像

CATiledLayer 到 CALayer

CATiledLayer 如何知道何时提供新图块?

在 CATiledLayer 中预加载/预显示图块?

如何使用 UIScrollView 和 CATiledLayer 在可缩放的 UIView 上绘制标记