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

发布于 2024-08-10 17:47:48 字数 858 浏览 2 评论 0原文

总之,

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

更具体地说,以下是我所看到的内容和我想要实现的目标的详细信息:

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

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

更新

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

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

如果有人有更好的解决方案,例如在重绘之前防止以重绘为目标的图块消失,我仍然很想听听它。

All,

I'm having trouble getting behavior that I want from CATiledLayer. Is there a way that I can trigger the tiles to redraw without having the side-effect that their areas are cleared to white first? I've already subclassed CATiledLayer to set fadeDuration to return 0.

To be more specific, here are the details of what I'm seeing and what I'm trying to achieve:

  • I have a UIScrollView with a big content size...~12000x800. Its content view is a UIView backed by a CATiledLayer.
  • The UIView is rendered with a lot of custom-drawn lines
  • Everything works fine, but the contents of the UIView sometimes change. When that happens, I'd like to redraw the tiles as seamlessly as possible. When I use setNeedsDisplay on the view, the tiles redraw but they are first cleared to white and there's a fraction-of-a-second delay before the new content is drawn. I've already subclassed CATiledLayer so that fadeDuration is set to 0.
  • The behavior that I want seems like it should be possible...when you zoom in on the scrollview and the content gets redrawn at a higher resolution, there's no blanking before the redraw; the new content is drawn right on top of the old one. That's what I'm looking for.

Thanks; I appreciate your ideas.

Update:

Just to follow up - I realized that the tiles weren't being cleared to white before the redraw, they're being taken out entirely; the white that I was seeing is the color of the view that's beneath my CATiledLayer-backed view.

As a quick hack/fix, I put a UIImageView beneath the UIScrollView, and before triggering a redraw of the CATiledLayer-backed view I render its visible section into the UIImageView and let it show. This smooths out the redraw significantly.

If anyone has a better solution, like keeping the redraw-targeted tiles from going away before being redrawn in the first place, I'd still love to hear it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

只有一腔孤勇 2024-08-17 17:47:48

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

但是,如果 levelOfDetail 与 LODB 不同,则对 setNeedsDisplayInRect: 的任何调用都会重绘所有图块。

I've found that if you set levelsOfDetailBias and levelsOfDetail both to the same value (2 in my case), then it only redraws the tiles that are touched by my setNeedsDisplayInRect: call, as you'd hope.

However if the levelsOfDetail is different to LODB, then any calls to setNeedsDisplayInRect: redraw all the tiles.

千鲤 2024-08-17 17:47:48

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

You could add another layer (possibly a CATiledLayer) behind the existing tiled layer. (Sort of a double-buffered solution.) You would call setNeedsDisplay: on the second layer from a timer that fires after a few seconds to ensure that that layer doesn't redraw at the same time as the front layer.

许一世地老天荒 2024-08-17 17:47:48

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

我想看看您如何实现您的应用程序。我花了数周时间寻找一个示例,该示例使用 UIScrollView 和 CATiledLayer-back 视图的组合以及大量自定义绘制的线条。苹果有一些很棒的示例代码 - 但它都涉及图像而不是线条艺术,所以对我没有帮助。

Another potential option is to use the same delegate to draw content to a bitmap context and swap the bitmap into the backing store once the content is refreshed. This should produce a flicker-free result. That being said, I can't tell you how this might be done, and one nice thing about CATiledLayers is they automatically generate tiles when you zoom and pregenerate tiles when you pan once zoomed in.

I would like to see how you implement your application. I have been looking for weeks to find an example that uses a combination of UIScrollView and a CATiledLayer-back view with a lot of custom drawn lines. Apple has some great sample code - but it all involves images rather than line art, so no help for me.

耶耶耶 2024-08-17 17:47:48

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

Having read through these answers without a solution, I discovered that tiling a page was the dominant background task.
Preparing my lo-res placeholder image on a high priority queue solved this issue - the images now appear while the tiling is occurring. Caching the placeholder images further improves their appearance - they appear before the tiling begins.
With newer devices, the tiling it so fast, these tricks might not matter. A sample PDF consisting of large scanned images (e.g. a scanned book) tiles the slowest in my experience, and makes for good test data.

悲念泪 2024-08-17 17:47:48

我在 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;

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

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

I had the same problem with iPad.

The solution was more simple than I thought and far more simple than using UIImageView to render display before redrawing... :

Just don't set any background color for the Layer!

I had CATiledLayer set in a similar way:

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;

Note that I have commented out the line setting layer's background color to white.
After that the white blank before redraw problem disappeared!

Let me know if anyone has tried that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文