2

I'm trying to get a screenshot image in my iOS app. The screenshot must have everything on the screen, including the status bar, so solutions such as this does not work for me. I tried the following:

override func viewDidLoad() {
    super.viewDidLoad()

    // Wait for one second before taking the screenshot.
    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { timer in
        // Get a view containing the screenshot, shrink it a little, and show it.
        let view = UIScreen.main.snapshotView(afterScreenUpdates: false)
        view.frame = view.frame.insetBy(dx: 18, dy: 32)
        self.view.addSubview(view)

        // Get the screenshot image from the view, and save it to the photos album.
        UIGraphicsBeginImageContextWithOptions(UIScreen.main.bounds.size, false, 0)
        view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)
    }
}

I ran the above code in iOS 11.4.1 on an iPhone 6 Plus. The screenshot was successfully captured and shown on the screen, but the image saved to the album was completely blank. What am I doing wrong? What's the correct way to capture a full screenshot?

Update

Per CZ54's suggestion, I inspected the value of the variable image in a debug session, and found out that it is completely blank, although its size is correct. So the key problem here is, how am I supposed to extract the image from a screenshot view returned by the UIScreen.main.snapshotView() method?

ycsun
  • 1,825
  • 1
  • 13
  • 21
  • add breakpoint, check your image before saving – CZ54 Aug 10 '18 at 10:11
  • @CZ54: I tried that and found that the image is of the correct size and is indeed blank. – ycsun Aug 10 '18 at 10:19
  • Replace timer by let deadlineTime = DispatchTime.now() + .seconds(1) DispatchQueue.main.asyncAfter(deadline: deadlineTime) { } – CZ54 Aug 10 '18 at 10:21

1 Answers1

0

Swift 4.1.1

   let deadlineTime = DispatchTime.now() + .seconds(1)
    // Wait for one second before taking the screenshot.
    DispatchQueue.main.asyncAfter(deadline: deadlineTime) {

        let view = UIScreen.main.snapshotView(afterScreenUpdates: false)
        view.frame = view.frame.insetBy(dx: 18, dy: 32)
        self.view.addSubview(view)

        // Get a view containing the screenshot, shrink it a little, and show it.
        UIGraphicsBeginImageContextWithOptions(self.view.frame.size, true, UIScreen.main.scale)
        //guard let context = UIGraphicsGetCurrentContext() else { return }
        //self.view.layer.render(in: context)
        self.view?.drawHierarchy(in:  self.view.bounds, afterScreenUpdates: true)
        guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return }
        UIGraphicsEndImageContext()

        //Save it to the camera roll
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
    }
Vishnu
  • 371
  • 1
  • 2
  • 17
  • Thanks for your answer. Unfortunately, although `self.view?.drawHierarchy()` does generate an image, this method doesn't work for me because the generated image doesn't contain the status bar. That is why I need to call `UIScreen.main.snapshotView()` because the screenshot view it generates contains the status bar. The key problem here is how to extract the image from the screenshot view. – ycsun Aug 10 '18 at 13:34