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

Posted

技术标签:

【中文标题】在 CATiledLayer 中预加载/预显示图块?【英文标题】:Preload/predisplay tiles in a CATiledLayer? 【发布时间】:2010-11-11 03:43:07 【问题描述】:

在 iPhone 上(尽管我认为这在 Cocoa 中同样有效)我有一个 UIScrollView 围绕一个由 CATiledLayer 支持的 UIView。默认情况下,它的工作方式是在我的视口滚动到 CATiledLayer 的空白部分时加载任何未缓存/未获取的图块。

我想知道是否有办法触发 CATiledLayer 加载未主动显示的图块?例如,我想预加载与当前显示的图块相邻的所有图块,而它们仍在屏幕外,从而避免在异步加载后闪烁的空白屏幕淡入图像。

有什么想法吗?

【问题讨论】:

你发现了吗?如果你这样做了,我真的很想知道你是怎么做到的。 不。从不做。 :( 使用 setNeedsDisplayInRect: 可以刷新已加载磁贴的内容,但似乎不会导致它预加载。 【参考方案1】:

我认为 CATiledLayer 不会做你想做的事。不过,还有其他几个选择。首先,您可以禁用磁贴淡入并使其立即显示,如下所示:

@interface NoFadeTiledLayer : CATiledLayer 

@end

@implementation NoFadeTiledLayer
+ (CFTimeInterval)fadeDuration 
    return 0.0;

@end

@implementation MyViewWithTiledLayer
+ (Class)layerClass 
    return [NoFadeTiledLayer class];

...
@end

其次,您可以对相邻的图块进行自己的预取和缓存,以便在 CATileLayer 调用 drawLayer:inContext 时准备好它们。我会实现scrollViewDidScroll:和scrollViewDidZoom:来确定相邻的图块和levelOfDetail。然后进行缓存查找并将任何不存在的内容添加到预取/渲染队列中。后台线程可以为队列提供服务,随后的滚动或缩放将清除并重建队列。然后让 drawLayer:inContext 先检查缓存,并在必要时仅获取/渲染。

【讨论】:

我已经尝试过这种预缓存方法(包括 no-fade-duration 层子类),不幸的是,它似乎没有多大帮助。我不知道为什么;这听起来确实是个好方法。【参考方案2】:

CATileLayer 是那些令人沮丧的类之一,它在一件事情上做得很好,但没有灵活性。

在这一点上,留给我们的只有创造力:

1) 使您的滚动视图变大。在我不再看到“空白”图块之前,我尝试了 5 倍的屏幕大小。小心内存使用!尽管用户只看到了 2% 的区域,但您正在绘制一个巨大的区域。

2) 有两个版本的图像,一个高分辨率和一个低分辨率。您应该能够非常快速地对低分辨率进行 blit,并且基本上您会得到“模糊”而不是“空白”图块。 Apple 的示例代码 ZoomingPDFViewer 向您展示了如何做到这一点。

http://developer.apple.com/library/ios/#samplecode/ZoomingPDFViewer/Introduction/Intro.html

当然,如果您想投入时间,两者的某种组合可能会奏效。

【讨论】:

所有好主意。我希望我能说出两个答案!【参考方案3】:

您应该尝试在您希望显示的区域上调用 setNeedsDisplayInRect:。如果您想保持在 tile 边界内,可以使用 tileSize 属性来计算 tile 边界。

但我不确定这是否会起作用,我们也不知道切片缓存机制是如何工作的。

【讨论】:

以上是关于在 CATiledLayer 中预加载/预显示图块?的主要内容,如果未能解决你的问题,请参考以下文章

选择 searchBar 时在 UISearchController 中预加载数据

在 Android 应用程序开发中预加载或预缓冲 .mp4 视频

在 Flutter 中预缓存 html 页面

在 SpriteKit 中预加载纹理

使用“预加载”链接指令在 Chrome 中预加载字体

Vue.js/Vuetify - 在 v-select 中预加载选项时的自动完成问题