UIScrollView w/ Large CATiledLayer + Overlay 可以快速渲染
Posted
技术标签:
【中文标题】UIScrollView w/ Large CATiledLayer + Overlay 可以快速渲染【英文标题】:UIScrollView w/ Large CATiledLayer + Overlay that renders fast 【发布时间】:2012-08-22 10:48:34 【问题描述】:我已经研究了几个星期了(ios),但我似乎无法找到一个可以接受的解决方案。
要求
显示 10000x10000 像素的背景图片 缩放和滚动响应 具有自定义绘图的顶部叠加层 叠加中的元素是交互式的(点击和突出显示元素等),并且可以打开或关闭片段。 iOS 4.0把它想象成一个虚构城镇的地理地图,上面绘制了一个由道路、线路、区域和建筑物组成的疯狂系统。 CGPaths 与各种不透明度填充、一些图标图像等的混合。它就像一个更复杂的谷歌地图应用程序版本。
我尝试过的:
1 - 多个 CATiled 层
查看层次结构:
滚动视图 ->容器视图 -->TiledView (CATiledLayer 10000x10000) --->OverlayView (CATiledLayer 10000x10000)结果: 左右从魔法苹果缓存中掉落瓷砖。两个 CATiledlayers 似乎不是正确的路径。覆盖的更新并不快。
2 - OverlayView 的 TiledView 子类
查看层次结构:
滚动视图 ->OverlayView(TiledView CATiledLayer 10000x10000 的子类)结果: 渲染覆盖更新的时间太长。 更新瓷砖很慢
3 - 带有单个容器视图的滚动视图
查看层次结构:
滚动视图 ->ContainerView (10000x10000) -->OverlayView (CALayer 10000x10000) -->TiledView (CATiledLayer 10000x10000)结果: 无法工作,因为 OverlayView 消耗太多内存。 TileView 很好,因为它有 CATiledLayer 支持
4 - OverlayView 使用滚动代理和 CTM 缩放/平移来模拟变大
查看层次结构:
OverlayView (CALayer 1024x768) 滚动视图 ->TiledView (CATiledLayer 10000x10000)结果: 我使用滚动视图代表来调整覆盖视图的偏移和缩放。这种方法的问题在于,drawrect 每秒调用 100 次,而覆盖视图的绘制速度不够快,因此它完全滞后到 1fps。
这就是我所在的位置。我觉得这最后一种方法很重要,但需要一些疯狂的工作来驯服drawrect的疯狂。其他想法是尝试在 OpenGL 中解决一些问题。
在我开始做这些之前,我想我会询问社区,看看他们在面对类似要求时会做什么/做了什么。
感谢您的帮助。
【问题讨论】:
【参考方案1】:我的建议是在您的滚动视图中有两个视图。背景 CATiledLayer 视图。第二个视图是位于背景视图上方的自定义 UIView - 这是您进行自定义绘图的地方。自定义视图应该有一个 drawRect: 方法,现在什么都不做。
所以你在你的 customView 中什么都没有尝试这个,并确保滚动等是你想要的。如果问题出在后台视图中并且您需要解决该问题。
此时,您的自定义视图开始绘制内容。请注意,您将在 drawRect 中获得要更新的矩形。也许您有一千个项目可能需要在整个画布上绘制 - 因此每个项目都有一个 frame 属性,因此您可以确定给定当前缩放和框架需要绘制的内容。你只画那些项目。
这种通用技术过去对我来说效果很好。
EDIT2:
所以在设备上运行时,我复制了“无法分配”消息。所以计划 B。你可以做的是有一个容器视图,它有两个视图——滚动视图和一个新的 UIView 子类。 scrollView 有巨大的怪物视图。子类视图有一个正好是 UIScrollView 框架的框架。
然后,您将确保收到 scrollView 消息“scrollViewDidScroll:”,可能还有其他消息。
当 scrollView 稳定时,或者您收到上述消息时,自定义 UIView 子类会收到一条消息,说 draw 但使用的偏移量是 scrollView contentOffset。
自定义类要做的工作是一样的。它没有使用它的 drawRect 原点,而是使用该点并通过 scrollView 的 contentOffset 偏移它。现在,当您绘制时,您正在寻找在 drawRect:rect 中通过滚动视图偏移正偏移的点范围内的对象。
【讨论】:
我基本上在示例 3 中尝试过。我得到 CoreAnimation 无法分配 15000000 字节错误(我认为这是在没有 catiledlayer 支持的情况下将 10000x10000 pt 视图添加到窗口的直接结果) .你是在暗示我不应该得到那个错误吗? 好吧,让我们来看看这个。首先,只有背景层正在工作(我假设尚未)所以如果你创建一个 UIView 子类,添加一个 drawRect: 方法(必须这样做,只是不要做任何事情),并将其添加到 scrollView 中,即失败?只是想确保这一点 - 我 相信 使用 drawRect 系统不会尝试制作支持层。 [我建议了一个类似的解决方案,所以一个月前的其他人,它似乎正在工作......] 我刚刚创建了一个新的 UIView 子类,它只是用空实现覆盖了 drawrect。我使用 CGRectMake(0,0,10000,10000) 初始化视图,然后将其与背景“TiledView”一起添加到滚动视图中。仍然得到CoreAnimation分配错误:\ 呃,MyCustomView *view = [MyCustomView alloc] initWithFrame:CGrectmake....]; - 那是你做的吗?好吧,我希望这会奏效……但如果没有,那就是 B 计划。 一直在不停地进行....但是对于您的编辑1,是的,但是当您在怪物视图上拥有这样的drawrect时,它会在设备上爆炸。现在对于edit2,我相信这与我在上面的第四种方法中的相同。除非我的理解不正确,否则问题是如果 scrollViewDidScroll 方法在覆盖视图上调用 setNeedsDisplay ,它会收到大量可笑的 drawrect 调用,并且几乎会使设备减速到急停。【参考方案2】:我曾经画过一张基于路径的地图,但我没有背景图片,只有路径。我只使用了一个带有drawrect的视图(没有滚动视图)并自己实现了滚动/缩放。那里存在一些性能问题,尤其是在具有高分辨率的 ipad3 上,因为它在分配全分辨率图像上下文时存在问题。
不要在路径上使用阴影等,这会影响性能。 预先计算路径/对象的所有边界框并按某种顺序存储它们,以便您可以尽快查找可见路径/对象。 为不同的缩放级别使用不同详细的路径集。但最后我认为 openGL 是更好的解决方案。
【讨论】:
【参考方案3】:老问题,但也适用于每个为此苦苦挣扎的人。您应该使用两个以相同方式缩放/滚动的平铺视图,但覆盖视图不应是背景视图的子视图。也就是说,您应该:
滚动视图 ->容器视图 -->TiledView (CATiledLayer 10000x10000) -->OverlayView (CATiledLayer 10000x10000)那么对于绘图速度,它真的归结为你如何为覆盖进行绘图。对于每个图块,您应该确保只绘制覆盖图块的内容,而不是所有其他位于图块边界之外的东西。
【讨论】:
以上是关于UIScrollView w/ Large CATiledLayer + Overlay 可以快速渲染的主要内容,如果未能解决你的问题,请参考以下文章
pumas are large,cat-like animals which are found in America.这句话are和found不都是动词
滚动应用:UIPageViewController vs UIScrollView