如何捕获当前视图屏幕截图并在代码中重用? (iPhone SDK)
Posted
技术标签:
【中文标题】如何捕获当前视图屏幕截图并在代码中重用? (iPhone SDK)【英文标题】:How to capture current view screenshot and reuse in code? (iPhone SDK) 【发布时间】:2009-05-18 18:15:22 【问题描述】:当用户旋转设备时,我正在尝试从一个 UIView 转换到另一个。这本身并不难。但是,由于我在旋转后显示的是完全不同的内容,所以 UIKit 提供的默认动画(旋转当前显示的视图)在概念上是不合适的。
简单地禁用动画并突然交换视图是可以容忍的,但远低于我正在构建到应用程序其余部分的润色。我更愿意这样做:
当调用 shouldAutorotateToInterfaceOrientation: 时,我想获取旋转前用户视图的不透明视图快照,如果你愿意,可以截屏。然后在旋转完成并且系统应用了视图变换等之后,我可以显示我保存的快照视图并将我选择的动画转换为我的新视图。完成后,我可以释放我的快照并继续前进。
有没有不花钱的方法?
我能想到的唯一其他选择是在除默认方向之外的所有方向上都返回 NO,然后通过应用我自己的动画和变换来做出反应。但是,我更喜欢使用系统来执行此操作,因为我觉得自己执行此操作可能会导致手动旋转视图中的“未定义”键盘行为等。
想法?
【问题讨论】:
我应该注意,我现在已经尝试了我提到的第二个选项:在返回 NO 后手动应用我自己的视图和变换来做出反应......并且键盘确实出现在错误的方向。如果我要朝着这个方向前进,我将无法纠正这种行为。 【参考方案1】:- (UIImage *)captureView:(UIView *)view
CGRect screenRect = [[UIScreen mainScreen] bounds];
UIGraphicsBeginImageContext(screenRect.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor blackColor] set];
CGContextFillRect(ctx, screenRect);
[view.layer renderInContext:ctx];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
在这里找到这个:
http://discussions.apple.com/thread.jspa?messageID=8358740
【讨论】:
这种方法有一个大问题:UIGraphicsGetImageFromCurrentImageContext()
泄漏内存(它创建的 UIImage 从未正确处理),至少在旧版本的操作系统中(5.0 似乎不再有这个问题)。【参考方案2】:
这段代码对我有用
- (UIImage *)captureScreenInRect:(CGRect)captureFrame
CALayer *layer;
layer = self.view.layer;
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextClipToRect (UIGraphicsGetCurrentContext(),captureFrame);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenImage;
【讨论】:
我遇到了这个问题。我在清晰的背景上渲染笔触,一旦我保存,它就会从某处为图像添加黑色背景。【参考方案3】:在 Mac 上这很简单...您只需要 -bitmapImageRepForCachingDisplayInRect:
,但当然 iPhone 没有这样的东西。
我想我会通过设置图形上下文并在其上调用[window drawRect:...]
来捕获屏幕的当前图像来解决这个问题。这有点不合规范,因为你不应该自己打电话给-drawRect:
。我会有点担心这样做的副作用,但它可能没问题。如果它是您控制的全屏视图,您当然可以将绘图代码从-drawRect:
中提升出来,这样您就不会直接调用它。
类似的方法是使用当前-presentationLayer
的CALayer -drawInContext:
。这可能会稍微“符合规范”,因为传递您自己的上下文是合法的。但我不知道您是否真的能够正确获取所有子视图。可能取决于您的 UIWindow 的性质。
无论如何,很好的问题。也许有人有更聪明的解决方案,但这是我攻击它的方式。
编辑:感谢 Rob Terrell 和他聪明的 UIApplication+TVOut.m,我被介绍了 到返回 CGImageRef 的私有方法 UIGetScreenImage()。如果您愿意使用私有方法,那对您来说是一个不错的选择。鉴于它的名称和功能,它在我看来相当稳定,似乎不太可能违反 Apple 的意图。我还在Air Source 上遇到了一个非常好的讨论。通读 cmets 以获得多个链接。
【讨论】:
如果你想在 App Store 上发布,使用 UIGetScreenImage() 会导致你的应用被拒绝。【参考方案4】:我可以保证 [window drawRect:] 不会起作用。大多数视图没有实现 drawRect: 并且它肯定不像在 mac 上那样递归。
drawInContext: 也非常相似,因为它从根本上要求图层绘制自己,而不是递归地绘制它的子图层。 “默认实现什么都不做。”说明一切。
我通过执行以下操作在应用商店中为 Clif Bar Save Our Snow 应用程序实现此功能:
递归遍历层层次结构,从每一层获取内容。如果它闻起来像图像,请使用 CGContext 方法将其绘制到您的上下文中。 在行走时,请确保在递归调用时应用每一层的变换/位置是的,相当大的痛苦。但是,是的,它运行得很好,并且被 Apple 解决了 :)。
【讨论】:
以上是关于如何捕获当前视图屏幕截图并在代码中重用? (iPhone SDK)的主要内容,如果未能解决你的问题,请参考以下文章
如何捕获同时包含 cocs2d 和 UIKit 的视图的屏幕截图
为啥在 layoutsubviews/viewdidlayoutsubviews 中捕获的视图的屏幕截图不是最终在屏幕上呈现的?