Senõr Ganso
Senõr Ganso

Reputation: 1734

How to take a screenshot of UIView on a background thread?

The app I'm working on has google maps on almost every screen. To save memory, I'm reusing the same google maps view everywhere. The problem is, when you pop a viewController, you can see a white space where the map was. To work around that I'm taking screenshots of it and adding as a background before removing the map. But there's another problem, taking a screenshot takes about 0.3 seconds on iPhoneX (I suppose it's even worse on older phones). Is there any way to take screenshots of UIView on a background thread?

Upvotes: 3

Views: 2881

Answers (3)

Faris Muhammed
Faris Muhammed

Reputation: 1028

I tried all the latest snapshot methods using swift. Other methods didn't work for me in the background. But taking snapshot this way worked for me.

create an extension with parameters view layer and view bounds.

extension UIView {
    func asImageBackground(viewLayer: CALayer, viewBounds: CGRect) -> UIImage {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: viewBounds)
            return renderer.image { rendererContext in
                viewLayer.render(in: rendererContext.cgContext)
            }
        } else {
            UIGraphicsBeginImageContext(viewBounds.size)
            viewLayer.render(in:UIGraphicsGetCurrentContext()!)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return UIImage(cgImage: image!.cgImage!)
        }
    }
}

Usage

DispatchQueue.main.async {
                let layer = self.selectedView.layer
                let bounds = self.selectedView.bounds
                DispatchQueue.global(qos: .background).async {
                    let image = self.selectedView.asImageBackground(viewLayer: layer, viewBounds: bounds)
                }
            }

We need to calculate layer and bounds in the main thread, then other operations will work in the background thread. It will give smooth user experience without any lag or interruption in UI.

Upvotes: 6

Hongwei Lv
Hongwei Lv

Reputation: 56

Actually ,it is possible! But first on UIThread you need get some infos Like this:

CALayer* layer = view.layer;
CGRect frame = view.frame;

, then change to backgroundthead use codes below to get image:

UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Upvotes: 4

Aline Kolczycki Borges
Aline Kolczycki Borges

Reputation: 172

From UIKit documentation

Use UIKit classes only from your app’s main thread or main dispatch queue, unless otherwise indicated. This restriction particularly applies to classes derived from UIResponder or that involve manipulating your app’s user interface in any way.

I don't think there is a way of snapshoting the view on the background thread because you are using an UIKit method.

Upvotes: 0

Related Questions