Search code examples
iosswiftviewscreenshot

Exclude View from Screenshot


This is how I take a screenshot of my view:

UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0)
view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

However, in the view, there is a UIVisualEffectsView which I'd like to exclude from the screenshot.
I tried hiding the UIVisualEffectsView just before taking the screenshot and un-hiding it afterwards but I don't want the user to see that process. (which he does if I simply hide the view because the iPad is too slow and it looks like the screen is flickering...)

Any ideas? Thanks in advance!


Solution

  • I would take advantage of the snapshotViewAfterScreenUpdates() method

    This method very efficiently captures the current rendered appearance of a view and uses it to build a new snapshot view. You can use the returned view as a visual stand-in for the current view in your app.

    Therefore you can use it in order to display an overlay UIView of the complete un-altered view hierarchy to the user while rendering a version of the hierarchy with your changes underneath it.

    The only caveat is that if you're capturing a view controller's hierarchy, you'll have to create a 'content view' subview in order to prevent the overlay view from being rendered in your screenshot where you make the changes to the hierarchy. You'll then want to add your view hierarchy that you want to render to this 'content view'.

    So your view hierarchy will want to look something like this:

    UIView // <- Your view
        overlayView // <- Only present when a screenshot is being taken
        contentView // <- The view that gets rendered in the screenshot
            view(s)ToHide // <- The view(s) that get hidden during the screenshot
    

    Although, if you are able to add the overlayView to the view's superview - instead of to the view itself – you don't need to mess about with the hierarchy at all. For example:

    overlayView // <- Only present when a screenshot is being taken
    UIView // <- Your view – You can render this in the screenshot
        view(s)ToHide // <- The view(s) that get hidden during the screenshot
        otherViews // <- The rest of your hierarchy
    

    Something like this should achieve the desired result:

    // get a snapshot view of your content
    let overlayView = contentView.snapshotViewAfterScreenUpdates(true)
    
    // add it over your view
    view.addSubview(overlayView)
    
    // do changes to the view heirarchy
    viewToHide.hidden = true
    
    // begin image context
    UIGraphicsBeginImageContextWithOptions(contentView.frame.size, false, 0.0)
    
    // render heirarchy
    contentView.drawViewHierarchyInRect(contentView.bounds, afterScreenUpdates: true)
    
    // get image and end context
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    
    // reverse changes to the view heirarchy
    viewToHide.hidden = false
    
    // remove the overlay view
    overlayView.removeFromSuperview()