如何在后台线程上截取 UIView 的屏幕截图?

Posted

技术标签:

【中文标题】如何在后台线程上截取 UIView 的屏幕截图?【英文标题】:How to take a screenshot of UIView on a background thread? 【发布时间】:2018-10-02 12:37:54 【问题描述】:

我正在开发的应用程序几乎每个屏幕上都有谷歌地图。为了节省内存,我到处重复使用相同的谷歌地图视图。问题是,当您弹出视图控制器时,您可以看到地图所在的空白区域。为了解决这个问题,我在删除地图之前对其进行截图并添加为背景。但是还有另一个问题,在 iPhoneX 上截屏大约需要 0.3 秒(我想在旧手机上更糟)。有没有办法在后台线程上截取 UIView 的截图?

【问题讨论】:

***.com/questions/42778797/… 。参考我的答案 您对我的问题投了反对票,但您的回答与此无关。再读一遍。我需要在背景线程上截屏。您的答案仅适用于主线程。 嘿,我为什么要对你的问题投反对票,伙计,我来这里是为了帮助其他人,我与你的问题没有任何关系,我没有对你的问题投反对票 我不认为你可以在后台线程中捕获屏幕截图,你必须在主线程中进行***.com/questions/52605016/… 【参考方案1】:

我使用 swift 尝试了所有最新的快照方法。其他方法在后台对我不起作用。但是以这种方式拍摄快照对我有用。

使用参数视图层和视图边界创建扩展。

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!)
        
    

用法

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)
                
            

我们需要在主线程中计算层和边界,然后其他操作将在后台线程中进行。它将提供流畅的用户体验,不会在 UI 中出现任何延迟或中断。

【讨论】:

【参考方案2】:

其实是可以的!但首先在 UIThread 上,您需要获取一些信息,如下所示:

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

,然后改成 backgroundthead 使用下面的代码来获取图像:

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

【讨论】:

我不断收到此消息“在从主线程访问引擎后,此应用程序正在从后台线程修改自动布局引擎。这可能导致引擎损坏和奇怪的崩溃。”。但一切似乎都奏效了。 但实际上这种截屏方法足够快,我什至不需要后台线程。【参考方案3】:

来自 UIKit documentation

除非另有说明,否则只能从应用的主线程或主调度队列中使用 UIKit 类。此限制特别适用于从 UIResponder 派生的类或涉及以任何方式操纵您应用的用户界面的类。

我认为没有办法在后台线程上对视图进行快照,因为您使用的是 UIKit 方法。

【讨论】:

以上是关于如何在后台线程上截取 UIView 的屏幕截图?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 MediaProjection API 从后台服务类中截取屏幕截图?

是否可以在截取uiview的屏幕截图时设置图像大小?

如何在不将其添加到子视图的情况下截取 uiview?

在iOS上的应用程序中截取屏幕截图的方法是什么?

如何在android上通过降低音量和电源键来截取屏幕截图?

左右滑动 UIView