如何在Swift中使用全屏截图?

时间:2014-08-22 14:03:20

标签: ios swift uiimage screenshot

我找到this code

func screenShotMethod() {
    //Create the UIImage
    UIGraphicsBeginImageContext(view.frame.size)
    view.layer.renderInContext(UIGraphicsGetCurrentContext())
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    //Save it to the camera roll
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}

我需要做些什么才能将所有其他元素(例如导航栏)添加到屏幕截图中?

18 个答案:

答案 0 :(得分:69)

让我解释一下当前代码的作用以及如何修改它以捕获全屏幕,而不仅仅是将答案抛出那里。

UIGraphicsBeginImageContext(view.frame.size)

此代码行创建一个与view大小相同的新图像上下文。这里要取消的主要内容是新图像上下文view 的大小相同。除非您想要捕获应用程序的低分辨率(非视网膜)版本,否则您可能应该使用UIGraphicsBeginImageContextWithOptions。然后,您可以传递0.0以获得与设备主屏幕相同的比例因子。

view.layer.renderInContext(UIGraphicsGetCurrentContext())

这行代码会将视图层渲染到当前图形上下文(这是您刚刚创建的上下文)。这里要带走的主要事情是只有view(及其子视图)被绘制到图像上下文中。

let image = UIGraphicsGetImageFromCurrentImageContext()

这行代码根据绘制到图形上下文中的内容创建UIImage对象。

UIGraphicsEndImageContext()

这行代码结束了图像上下文。它已经清理了(你创建了上下文,也应该删除它。


结果是与view大小相同的图片,其中view及其子视图被吸引到其中。

如果要将所有内容绘制到图像中,则应创建一个与屏幕大小相同的图像,并将屏幕上的所有内容绘制到其中。在实践中,您可能只是在关键窗口中讨论所有内容"你的申请。由于UIWindowUIView的子类,因此也可以将其绘制到图像上下文中。

答案 1 :(得分:51)

Swift 4

    /// Takes the screenshot of the screen and returns the corresponding image
    ///
    /// - Parameter shouldSave: Boolean flag asking if the image needs to be saved to user's photo library. Default set to 'true'
    /// - Returns: (Optional)image captured as a screenshot
    open func takeScreenshot(_ shouldSave: Bool = true) -> UIImage? {
        var screenshotImage :UIImage?
        let layer = UIApplication.shared.keyWindow!.layer
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
        guard let context = UIGraphicsGetCurrentContext() else {return nil}
        layer.render(in:context)
        screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        if let image = screenshotImage, shouldSave {
            UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
        }
        return screenshotImage
    }

更新了Swift 2

您提供的代码有效,但不允许您捕获屏幕截图中的NavigationBarStatusBar。如果您想截取包含NavigationBar的设备的屏幕截图,则必须使用以下代码:

func screenShotMethod() {
    let layer = UIApplication.sharedApplication().keyWindow!.layer
    let scale = UIScreen.mainScreen().scale
    UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);

    layer.renderInContext(UIGraphicsGetCurrentContext()!)
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    UIImageWriteToSavedPhotosAlbum(screenshot, nil, nil, nil)
}

使用此代码:

  • 首次启动应用并调用此方法时,iOS设备会询问您是否允许将图像保存在相机胶卷中。
  • 此代码的结果将是.JPG图像。
  • StatusBar不会出现在最终图片中。

答案 2 :(得分:21)

Swift 3示例:

func captureScreen() -> UIImage? {
    guard let context = UIGraphicsGetCurrentContext() else { return .none }
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
    view.layer.render(in: context)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}

答案 3 :(得分:20)

详细

  • Xcode 9.3,Swift 4.1
  • Xcode 10.2(10E125),Swift 5

在iOS上测试:9,10,11,12

解决方案

 imageView.image = UIApplication.shared.screenShot

用法

import UIKit

extension UIApplication {

    var screenShot: UIImage?  {

        if let layer = keyWindow?.layer {
            let scale = UIScreen.main.scale

            UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
            if let context = UIGraphicsGetCurrentContext() {
                layer.render(in: context)
                let screenshot = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return screenshot
            }
        }
        return nil
    }
}

详细

Xcode 8.2.1,swift 3

适用于iOS 10x的版本1

import UIKit

extension UIApplication {

    var screenShot: UIImage?  {

        if let rootViewController = keyWindow?.rootViewController {
            let scale = UIScreen.main.scale
            let bounds = rootViewController.view.bounds
            UIGraphicsBeginImageContextWithOptions(bounds.size, false, scale);
            if let _ = UIGraphicsGetCurrentContext() {
                rootViewController.view.drawHierarchy(in: bounds, afterScreenUpdates: true)
                let screenshot = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return screenshot
            }
        }
        return nil
    }
}

iOS 9x版本2,10x

  

如果您尝试在iOS 9x中使用版本1代码,则会出现错误: CGImageCreateWithImageProvider:无效的图像提供程序:NULL。

let screenShot = UIApplication.shared.screenShot!

用法

{{1}}

答案 4 :(得分:9)

为方便起见,我会在其自己的文件中添加一个扩展名

import UIKit

  public extension UIWindow {

    func capture() -> UIImage {

      UIGraphicsBeginImageContextWithOptions(self.frame.size, self.opaque, UIScreen.mainScreen().scale)
      self.layer.renderInContext(UIGraphicsGetCurrentContext()!)
      let image = UIGraphicsGetImageFromCurrentImageContext()
      UIGraphicsEndImageContext()

      return image
  }
}

按以下方式拨打分机...

let window: UIWindow! = UIApplication.sharedApplication().keyWindow

let windowImage = window.capture()

同样,人们可以扩展UIView来捕捉那个......的图像。

答案 5 :(得分:4)

在iOS 10中创建上下文的推荐方法是使用UIGraphicsImageRenderer

extension UIView {
    func capture() -> UIImage? {
        var image: UIImage?

        if #available(iOS 10.0, *) {
            let format = UIGraphicsImageRendererFormat()
            format.opaque = isOpaque
            let renderer = UIGraphicsImageRenderer(size: frame.size, format: format)
            image = renderer.image { context in
                drawHierarchy(in: frame, afterScreenUpdates: true)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(frame.size, isOpaque, UIScreen.main.scale)
            drawHierarchy(in: frame, afterScreenUpdates: true)
            image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
        }

        return image
    }
}

答案 6 :(得分:3)

我使用这种方法:

func captureScreen() -> UIImage {
    var window: UIWindow? = UIApplication.sharedApplication().keyWindow
    window = UIApplication.sharedApplication().windows[0] as? UIWindow
    UIGraphicsBeginImageContextWithOptions(window!.frame.size, window!.opaque, 0.0)
    window!.layer.renderInContext(UIGraphicsGetCurrentContext())
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image;
}

它捕获除状态栏以外的所有内容,并且它不会要求允许在相机胶卷中保存图像。

希望它有所帮助!

答案 7 :(得分:2)

快捷键5

如果您只需要在那一瞬间获得屏幕的真实快照(带有键盘和状态栏):

snap

UIViewview.addSubview(snap) ,其边框自动设置为屏幕的边界。现在将其添加到视图控制器的视图中将为您提供显示为冻结状态的UI:

func getAllWiFiNameList() -> String? {
            var ssid: String?
            if let interfaces = CNCopySupportedInterfaces() as NSArray? {
            for interface in interfaces {
            if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
                        ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
                        break
                    }
                }
            }
            return ssid
        }

不需要扩展和所有不必要的东西-两行代码就足够了。

答案 8 :(得分:1)

  // Full Screen Shot function. Hope this will work well in swift.
  func screenShot() -> UIImage {                                                    
    UIGraphicsBeginImageContext(CGSizeMake(frame.size.width, frame.size.height))
    var context:CGContextRef  = UIGraphicsGetCurrentContext()
    self.view?.drawViewHierarchyInRect(frame, afterScreenUpdates: true)
    var screenShot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext();  
    return screenShot
  }

答案 9 :(得分:1)

UIWindow的Swift 3扩展程序

public extension UIWindow {

  func capture() -> UIImage? {

    UIGraphicsBeginImageContextWithOptions(self.frame.size, self.isOpaque, UIScreen.main.scale)
    self.layer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return image

  }
}]

答案 10 :(得分:1)

这是类似的,希望将来可以帮助某人。

self.view.image() //returns UIImage

这是一个Swift 3解决方案

https://gist.github.com/nitrag/b3117a4b6b8e89fdbc12b98029cf98f8

答案 11 :(得分:0)

  

view.snapshotView(afterScreenUpdates:true)

答案 12 :(得分:0)

我的版本还捕获了一个键盘。雨燕4.2

extension UIApplication {

    var screenshot: UIImage? {
        UIGraphicsBeginImageContextWithOptions(UIScreen.main.bounds.size, false, 0)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        for window in windows {
            window.layer.render(in: context)
        }
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

}

答案 13 :(得分:0)

Swift 4或更高版本。

用于扩展并通过您捕获的UIView进行呼叫。

声明

extension UIView {

    func viewCapture() -> UIImage? {

        UIGraphicsBeginImageContext(self.frame.size)

        guard let cgContext = UIGraphicsGetCurrentContext() else {
        print("Fail to get CGContext")
        return nil

    }
    self.layer.render(in: cgContext)

    guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
        print("Fail to get Image from current image context")
        return nil
    }
    UIGraphicsEndImageContext()

    return image

    }
}

用法

var m_image = UIImage()

if let tempCaptureImg = self.m_Capture_View.viewCapture() {
    viewController.m_image = tempCaptureImg
}

// m_Capture_View是UIView的类型

答案 14 :(得分:0)

这就是我在Swift 4中的操作方法

let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);                 
layer.render(in: UIGraphicsGetCurrentContext()!)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

现在屏幕截图将为UIImage

答案 15 :(得分:0)

Swift 5 iOS 13

一起使用

对于那些希望为函数提供快速答案以将 view 的屏幕截图作为UIImage返回的人:

func getScreenshot() -> UIImage? {
    //creates new image context with same size as view
    // UIGraphicsBeginImageContextWithOptions (scale=0.0) for high res capture
    UIGraphicsBeginImageContextWithOptions(view.frame.size, true, 0.0)

    // renders the view's layer into the current graphics context
    if let context = UIGraphicsGetCurrentContext() { view.layer.render(in: context) }

    // creates UIImage from what was drawn into graphics context
    let screenshot: UIImage? = UIGraphicsGetImageFromCurrentImageContext()

    // clean up newly created context and return screenshot
    UIGraphicsEndImageContext()
    return screenshot
}

我通过考虑问题中的代码并遵循DavidRönnqvist的建议(感谢您的解释)并进行了一些调整来拼凑出这个答案。

要包括导航栏和其他附加功能,请从窗口而不是 view 调用此方法。

我只需要一个函数来获取视图的屏幕截图,所以我希望这可以帮助寻找相同视图的任何人

答案 16 :(得分:0)

此代码是最新版本-100%有效

func getScreenshoot() -> UIImage {
    var window: UIWindow? = UIApplication.shared.keyWindow
    window = UIApplication.shared.windows[0] as? UIWindow
    UIGraphicsBeginImageContextWithOptions(window!.frame.size, window!.isOpaque, 0.0)
    window!.layer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image!;
}

答案 17 :(得分:0)

Swift 5

捕获整个屏幕(减去状态栏)而不会在较新的设备(如 iPhone 12 Pro)上崩溃

extension UIApplication {
    func getScreenshot() -> UIImage? {
        guard let window = keyWindow else { return nil }
        let bounds = UIScreen.main.bounds
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0)
        window.drawHierarchy(in: bounds, afterScreenUpdates: true)
        guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return nil }
        UIGraphicsEndImageContext()
        return image
    }
}

之前使用 UIApplication.shared.keyWindow?.layer.render(in: context) 的解决方案会导致某些设备(如 iPhone 12 Pro)出现内存崩溃。