How can I take a snapshot of a UIView that isn'

2019-01-18 01:09发布

问题:

I use this method for taking a snapshot:

UIView *snapshotView = [someView snapshotAfterScreenUpdates:NO];

This gives me a UIView that I can play with.

But, I need the UIImage of it and not the UIView.

This is the method I use for converting a UIView to an UIImage:

- (UIImage *)snapshotOfView:(UIView *)view
{
    UIImage *snapshot;

    UIGraphicsBeginImageContext(view.frame.size);

    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    snapshot = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return snapshot;
}

It doesn't work, the snapshot is a blank UIImage because the snapshotView isn't rendered.

The obvious thing to do is to directly take a snapshot of the view instead of taking the snapshot in the form of a UIView and then converting it.

The problem with the obvious method is that I'm using a WKWebView that has a huge bug that doesn't allow you to take screenshots. And that's true, I even reported the bug and they said they are trying to fix it.

So, how can I take the snapshot (UIImage) of the snapshotView without rendering it?

回答1:

drawViewHierarchyInRect will work for you. You can use this directly on your WKWebView.

There is some useful detail on this Apple Technical Q&A. Also I touch on it here in answer to a slightly different question.

I use it in a category on UIView:

@implementation UIView (ImageSnapshot)
- (UIImage*)imageSnapshot {
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, 
                                    YES, self.contentScaleFactor);
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
@end

I don't know what you mean by 'the obvious method' - but I have tested this on a WKWebView and it works.



回答2:

Since accepter answer didn't worked for me (UIGraphicsGetImageFromCurrentImageContext() returned nil all the time) I found different solution for iOS10+:

let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { _ in view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) }

P.S. You may want to call updateConstraintsIfNeeded() and layoutIfNeeded() before rendering