在CATiledLayer中预加载/预先显示磁贴?

时间:2022-04-11 08:58:14

On the iPhone (though I imagine it's an equally valid question in Cocoa) I have a UIScrollView around a UIView backed by a CATiledLayer. The way it works by default is to load any uncached/unfetched tiles when my viewport scrolls over a blank section of the CATiledLayer.

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

What I would like to know is if there's a way to trigger CATiledLayer to load a tile that's not actively being displayed? I would like to, for example, preload all tiles contiguous to the currently displayed tile while they are still offscreen, thus avoiding flashing a blank screen that fades in to the image once it's loaded asynchronously.

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

Any ideas?

有任何想法吗?

3 个解决方案

#1


14  

I don't think CATiledLayer will do what you want. There are a couple of other options though. First you can disable the tile fade-in and have it display immediately with something like this:

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

@interface NoFadeTiledLayer : CATiledLayer {
}
@end

@implementation NoFadeTiledLayer
+ (CFTimeInterval)fadeDuration {
    return 0.0;
}
@end

@implementation MyViewWithTiledLayer
+ (Class)layerClass {
    return [NoFadeTiledLayer class];
}
...
@end

Second, you can do your own pre-fetch and caching of the adjacent tiles so they're ready to go when CATileLayer calls drawLayer:inContext. I'd implement scrollViewDidScroll: and scrollViewDidZoom: to determine the adjacent tiles and levelOfDetail. Then do a cache lookup and add any not present to a pre-fetch/render queue. A background thread could service the queue and subsequent scrolls or zooms would clear and rebuild the queue. Then have drawLayer:inContext check the cache first and only fetch/render if necessary.

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

#2


4  

CATileLayer is one of those frustrating classes where it does one thing great, but has no flexibility to it.

CATileLayer是令人沮丧的课程之一,它做了一件好事,但没有灵活性。

At this point all that's left to us is creativity:

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

1) Make your scroll view huge. I tried 5x the size of the screen before I stopped seeing "blank" tiles. Be wary of memory use! You are drawing to a huge area even though the user only sees 2% of it.

1)使您的滚动视图变得巨大。在我看到“空白”瓷砖之前,我尝试了5倍大小的屏幕。警惕记忆的使用!即使用户只看到2%,你也会画到一个巨大的区域。

2) Have two version of your image, one high res and one low res. you should be able to blit the low res very quickly and basically you get "blurry" instead of "blank" tiles. Apple's sample code ZoomingPDFViewer shows you how to do this.

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

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

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

Of course, some combination of the two might work if you want to invest the time.

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

#3


0  

You should try calling setNeedsDisplayInRect: on the areas you wish to display. If you want to keep within tile boundaries you can use the tileSize property to compute tile boundaries.

您应该尝试在要显示的区域上调用setNeedsDisplayInRect :.如果要保留在切片边界内,可以使用tileSize属性来计算切片边界。

But I do not know for sure if this will work and we do not know how the tile caching mechanism works.

但我不确定这是否有效,我们不知道tile缓存机制是如何工作的。

#1


14  

I don't think CATiledLayer will do what you want. There are a couple of other options though. First you can disable the tile fade-in and have it display immediately with something like this:

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

@interface NoFadeTiledLayer : CATiledLayer {
}
@end

@implementation NoFadeTiledLayer
+ (CFTimeInterval)fadeDuration {
    return 0.0;
}
@end

@implementation MyViewWithTiledLayer
+ (Class)layerClass {
    return [NoFadeTiledLayer class];
}
...
@end

Second, you can do your own pre-fetch and caching of the adjacent tiles so they're ready to go when CATileLayer calls drawLayer:inContext. I'd implement scrollViewDidScroll: and scrollViewDidZoom: to determine the adjacent tiles and levelOfDetail. Then do a cache lookup and add any not present to a pre-fetch/render queue. A background thread could service the queue and subsequent scrolls or zooms would clear and rebuild the queue. Then have drawLayer:inContext check the cache first and only fetch/render if necessary.

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

#2


4  

CATileLayer is one of those frustrating classes where it does one thing great, but has no flexibility to it.

CATileLayer是令人沮丧的课程之一,它做了一件好事,但没有灵活性。

At this point all that's left to us is creativity:

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

1) Make your scroll view huge. I tried 5x the size of the screen before I stopped seeing "blank" tiles. Be wary of memory use! You are drawing to a huge area even though the user only sees 2% of it.

1)使您的滚动视图变得巨大。在我看到“空白”瓷砖之前,我尝试了5倍大小的屏幕。警惕记忆的使用!即使用户只看到2%,你也会画到一个巨大的区域。

2) Have two version of your image, one high res and one low res. you should be able to blit the low res very quickly and basically you get "blurry" instead of "blank" tiles. Apple's sample code ZoomingPDFViewer shows you how to do this.

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

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

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

Of course, some combination of the two might work if you want to invest the time.

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

#3


0  

You should try calling setNeedsDisplayInRect: on the areas you wish to display. If you want to keep within tile boundaries you can use the tileSize property to compute tile boundaries.

您应该尝试在要显示的区域上调用setNeedsDisplayInRect :.如果要保留在切片边界内,可以使用tileSize属性来计算切片边界。

But I do not know for sure if this will work and we do not know how the tile caching mechanism works.

但我不确定这是否有效,我们不知道tile缓存机制是如何工作的。