UIView 的快照视图在上下文中渲染/绘制,没有任何内容
Posted
技术标签:
【中文标题】UIView 的快照视图在上下文中渲染/绘制,没有任何内容【英文标题】:snapshotView of UIView render/draw in context with nothing 【发布时间】:2015-03-15 12:49:15 【问题描述】:我正在尝试在上下文中渲染/绘制 UIView 的快照视图以获取 UIImage。然后将其设置为 CAlayer.contents。 我尝试这种方法来获取快照视图:
snapshotViewAfterScreenUpdates:
然后将 UIView 转换为 UIImage:
UIGraphicsBeginImageContext(view.bounds.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
//I'm trying this method too
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
问题是我正在使用上面的代码,但我得到一个空图像。
【问题讨论】:
在 Apple 的文档中,snapshotViewAfterScreenUpdates
无法在上下文中呈现。如果需要快照图像,请尝试[window.layer.presentationLayer drawViewHierarchyInRect. window.bounds afterScreenUpdates:NO]
presentationLayer
将复制图层对象,该对象代表图层当前显示在屏幕上的状态。
【参考方案1】:
如果您首先需要快照 UIImage,只需使用第二个代码块中的方法。创建一个 UIView 的类别,如
@implementation UIView (takeSnapshot)
- (UIImage *)takeASnapshot
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
@end
够了。您不需要快照视图并将其转换为图像。在您的情况下,此过程可能会导致问题
【讨论】:
谢谢,这对我有用。我通过更改一些代码来修复我的项目,但我真的很想知道我的情况会发生什么。 Apple 'doc: 如果您想对快照应用图形效果(例如模糊),请改用 drawViewHierarchyInRect:afterScreenUpdates: 方法。【参考方案2】:在使用 floating snapshots
构建交互式动画时遇到了类似的问题。这是我们所做的:
UIView 扩展:
extension UIView
public func snapshot(scale: CGFloat = 0, isOpaque: Bool = false, afterScreenUpdates: Bool = true) -> UIImage?
UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, scale)
drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
public enum CASnapshotLayer: Int
case `default`, presentation, model
/// The method drawViewHierarchyInRect:afterScreenUpdates: performs its operations on the GPU as much as possible
/// In comparison, the method renderInContext: performs its operations inside of your app’s address space and does
/// not use the GPU based process for performing the work.
/// https://***.com/a/25704861/1418981
public func caSnapshot(scale: CGFloat = 0, isOpaque: Bool = false,
layer layerToUse: CASnapshotLayer = .default) -> UIImage?
var isSuccess = false
UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, scale)
if let context = UIGraphicsGetCurrentContext()
isSuccess = true
switch layerToUse
case .default:
layer.render(in: context)
case .model:
layer.model().render(in: context)
case .presentation:
layer.presentation()?.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return isSuccess ? image : nil
使用示例(互动动画内):
private func makeSnapshot(view: UIView, snapshotLayer: UIView.CASnapshotLayer) -> UIView?
// There is 3 ways for taking snapshot:
// 1. Replicate view: `view.snapshotView(afterScreenUpdates: true)`
// 2. Draw Hierarchy: `view.drawHierarchy(in: bounds, afterScreenUpdates: true)`
// 3. Render Layer: `layer.render(in: context)`
//
// Only #3 is working reliable during UINavigation controller animated transitions.
// For modally presented UI also trick by combining #1 and #2 seems works.
// I.e. `view.snapshotView(afterScreenUpdates: true).snapshot()`
//
// If this call causes error listed below, then this indicate that something wrong with one of the views layout.
// [Snapshotting] View (_UIReplicantView) drawing with afterScreenUpdates:YES inside CoreAnimation commit is not supported.
// See also: https://***.com/a/29676207/1418981
if let image = view.caSnapshot(layer: snapshotLayer)
let imageView = ImageView(image: image)
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFit
shapshots[view] = image
return imageView
return nil
【讨论】:
哇,多么棒的解决方案。在 Swift 5 上测试并运行 当控制器模态呈现时我无法工作以上是关于UIView 的快照视图在上下文中渲染/绘制,没有任何内容的主要内容,如果未能解决你的问题,请参考以下文章
在 XCTest 测试中从情节提要加载的视图控制器中清空 UIView 快照(间歇性)