在 UIScrollView 中拍摄 CATiledLayer 支持的视图的图像快照

Posted

技术标签:

【中文标题】在 UIScrollView 中拍摄 CATiledLayer 支持的视图的图像快照【英文标题】:taking image snapshot of CATiledLayer-backed view in UIScrollView 【发布时间】:2012-02-25 16:49:47 【问题描述】:

我有一个由UIScrollView 组成的自定义地图视图。滚动视图的子视图由CATiledLayer 支持。在这里一切都很好。平移和缩放会加载新的地图图块,一切都运行良好。

我想要做的是捕捉动画视频帧到这个滚动视图。本质上,我想为滚动视图的contentOffsetzoomScale 创建动画更改视频。

我知道这个概念是合理的,因为我可以使用私有 API 函数 UIGetScreenImage() 以例如 10fps 的速度捕获应用程序的屏幕,组合这些图像,我可以得到流畅的播放动画并使用时序曲线通过滚动视图动画。

当然,我的问题是我不能使用私有 API。通过 Apple here 概述的替代方案,我得到了一个几乎可以说是有效的选择:询问 CALayerrenderInContext 并从中获取 UIGraphicsGetImageFromCurrentImageContext()

不过,这似乎不适用于 CATiledLayer 支持的视图。捕获的是块状、未缩放的图像,就好像从未加载更高分辨率的图块一样。这在一定程度上是有道理的,因为CATiledLayer 会在后台线程中获取性能并且从主线程调用renderInContext 可能无法捕获这些更新。即使我也渲染了平铺层的presentationLayer,结果也是相似的。

在包含滚动视图的动画过程中,是否有 Apple 认可的方法来捕获支持 CATiledLayer 的视图的图像?或者在任何时候,就此而言?

【问题讨论】:

有人在这里发布了答案:***.com/questions/5526545/… 【参考方案1】:

顺便说一句,如果您在 CATiledLayer 支持的视图中正确实施 renderLayer:inContext:,这是可行的。

【讨论】:

【参考方案2】:

我做了一个快速测试,并且在包裹滚动视图的视图上使用 renderInContext: 似乎有效。你试过吗?

【讨论】:

是的。我已经提供了一些更简洁地演示了这个问题的示例代码:github.com/incanus/TiledLayerSnapTest 请注意,普通的UIView 的捕获工作正常,但CATiledLayer 支持的视图出现空白灰色。【参考方案3】:

此代码对我有用。

- (UIImage *)snapshotImageWithView:(CCTiledImageScrollView *)view

// Try our best to approximate the best tile set zoom scale to use
CGFloat tileScale;
if (view.zoomScale >= 0.5) 
    tileScale = 2.0;

else if (view.zoomScale >= 0.25) 
    tileScale = 1.0;

else 
    tileScale = 0.5;


// Calculate the context translation based on how far zoomed in or out.
CGFloat translationX = -view.contentOffset.x;
CGFloat translationY = -view.contentOffset.y;
if (view.contentSize.width < CGRectGetWidth(view.bounds)) 
    CGFloat deltaX = (CGRectGetWidth(view.bounds) - view.contentSize.width) / 2.0;
    translationX += deltaX;

if (view.contentSize.height < CGRectGetHeight(view.bounds)) 
    CGFloat deltaY = (CGRectGetHeight(view.bounds) - view.contentSize.height) / 2.0;
    translationY += deltaY;


// Pass the tileScale to the context because that will be the scale used in drawRect by your CATiledLayer backed UIView
UIGraphicsBeginImageContextWithOptions(CGSizeMake(CGRectGetWidth(view.bounds) / view.zoomScale, CGRectGetHeight(view.bounds) / view.zoomScale), NO, tileScale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, translationX / view.zoomScale, translationY / view.zoomScale);

// The zoomView is a subview of UIScrollView. The CATiledLayer backed UIView is a subview of the zoomView.
[view.zoomView.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return image;

在这里找到完整的示例代码:https://github.com/gortega56/CCCanvasView

【讨论】:

以上是关于在 UIScrollView 中拍摄 CATiledLayer 支持的视图的图像快照的主要内容,如果未能解决你的问题,请参考以下文章

在 UIScrollView 中居中 UIButtons

UIScrollView 子视图中滚动事件的锁定处理(在 UIScrollView 超级视图内)

在间隔拍摄会话中拍摄多张照片?

在 UIScrollView 中旋转 UIViewControllers

如何在 UiScrollview 中获取子视图的内容

在 UIScrollView 中同时缩放多个对象