Reputation: 534925
To capture my app's interface for testing purposes, I'm calling
let snapview = UIScreen.main.snapshotView(afterScreenUpdates: true)
This works fine on the simulator. But on my device (2nd generation iPhone SE), running from Xcode, we get a blank white view. Is this a known issue? I can draw the UIWindow's hierarchy as a workaround, but the result is not as true-to-life for certain things.
As a demo, I have created a project:
https://github.com/mattneub/ScreenSnapshotViewTest
Run this on your device. Tap the button. If you see a small yellow rectangle in the big red background, the screen capture is working. But if you see a small white rectangle in the big red background, the screen capture is failing. I see the yellow in the simulators but the white on my device.
Upvotes: 2
Views: 924
Reputation: 21
I think UIScreen.main.snapshotView(afterScreenUpdates: true) work does not the way you expect behavior.
It seems that this function create transparent visual filter and display all views in frozen state behind him, like stamp
You need add snapview like subview to main view, execute needed operation and then remove added view from superview
view.addSubview(snapview)
...do something...
snapview.removeFromSuperview()
And of course you have to handle the flash effect when adding and removing
view.layer.opacity = 0
UIView.animate(withDuration: 0.25) {
view.layer.opacity = 1
}
Tested on iPhone6s (iOS 14.6 Xcode 12.5.1)
ScreenCapturer.swift
static func capture(view: UIView) {
let snapview = UIScreen.main.snapshotView(afterScreenUpdates: true)
let renderer = UIGraphicsImageRenderer(size: snapview.bounds.size)
let image = renderer.image { _ in
view.addSubview(snapview)
view.drawHierarchy(in: snapview.bounds, afterScreenUpdates: true)
snapview.removeFromSuperview()
}
if let data = image.jpegData(compressionQuality: 0.8) {
do {
let url = try captureFileUrlNow()
try data.write(to: url)
print(url) // so we can check manually what got written in simulator
} catch {
print("ERROR:", error)
}
}
}
Function call from ViewController.swift
ScreenCapturer.capture(view: self.view)
To test the behavior of UIView.snapshotView() you can delete UIScreen.main.snapshotView (afterScreenUpdates: true) altogether and create a new UIView with the appropriate screen size, and this will be correct
static func capture(view: UIView) {
var snapview = UIView(frame: view.frame)
snapview = view.snapshotView(afterScreenUpdates: false)!
let renderer = UIGraphicsImageRenderer(size: snapview.bounds.size)
let image = renderer.image { _ in
view.addSubview(snapview)
view.drawHierarchy(in: snapview.bounds, afterScreenUpdates: true)
snapview.removeFromSuperview()
}
if let data = image.jpegData(compressionQuality: 0.8) {
do {
let url = try captureFileUrlNow()
try data.write(to: url)
print(url) // so we can check manually what got written in simulator
} catch {
print("ERROR:", error)
}
}
}
In general, UIView.snapshotView() is convenient to use to create a menu with the main view sliding to the side (or anywhere else), so you will be sure that when the main view returns, you will not interact with the elements and accidentally cause unwanted behavior with the view elements (clicking buttons, gesture recognition, or something else)
Note: This method is not suitable for creating a screenshot of the screen if there is an element with a live video from the camera, there will be an empty area, in this case it is necessary to take a photo from the camera and overlay a snapshot of the elements
Upvotes: 2