ios 如何在 Swift 中进行全屏截图?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25448879/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I take a full screen Screenshot in Swift?
提问by Pietro La Spada
I've found 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)
}
What do I need to do to get all the other elements, like the navigation bar, into the screenshots?
我需要做什么才能将所有其他元素(例如导航栏)添加到屏幕截图中?
回答by David R?nnqvist
Instead of just throwing the answer out there, let me explain what your current code does and how to modify it to capture the full screen.
让我解释一下您当前的代码是做什么的,以及如何修改它以捕获全屏,而不是直接给出答案。
UIGraphicsBeginImageContext(view.frame.size)
This line of code creates a new image context with the same size as view
. The main thing to take away here is that the new image context is the same size as view
. Unless you want to capture a low resolution (non-retina) version of your application, you should probably be using UIGraphicsBeginImageContextWithOptions
instead. Then you can pass 0.0
to get the same scale factor as the devices main screen.
这行代码创建了一个大小与view
. 这里要带走的主要内容是新的图像上下文与view
. 除非您想捕获应用程序的低分辨率(非视网膜)版本,否则您可能应该使用它UIGraphicsBeginImageContextWithOptions
。然后你可以通过0.0
获得与设备主屏幕相同的比例因子。
view.layer.renderInContext(UIGraphicsGetCurrentContext())
This line of code will render the view's layer into the current graphics context (which is the context you just created). The main thing to take away here is that only view
(and its subviews) are being drawn into the image context.
这行代码将视图层渲染到当前图形上下文(即您刚刚创建的上下文)中。这里要带走的主要内容是只有view
(及其子视图)被绘制到图像上下文中。
let image = UIGraphicsGetImageFromCurrentImageContext()
This line of code creates an UIImage object from what has been drawn into the graphics context.
这行代码根据已绘制到图形上下文中的内容创建一个 UIImage 对象。
UIGraphicsEndImageContext()
This line of code ends the image context. It's clean up (you created the context and should remove it as well.
这行代码结束了图像上下文。它是清理(您创建了上下文并且也应该将其删除。
The result is an image that is the same size as view
, with view
and its subviews drawn into it.
结果是一个与 , 大小相同的图像view
,其中view
绘制了它的子视图。
If you want to draw everything into the image, then you should create an image that is the size of the screen and draw everything that is on screen into it. In practice, you are likely just talking about everything in the "key window" of your application. Since UIWindow
is a subclass of UIView
, it can be drawn into a image context as well.
如果要将所有内容都绘制到图像中,那么您应该创建一个与屏幕大小相同的图像,并将屏幕上的所有内容都绘制到其中。实际上,您可能只是在谈论应用程序“关键窗口”中的所有内容。由于UIWindow
是 的子类UIView
,因此也可以将其绘制到图像上下文中。
回答by Imanou Petit
Swift 4
斯威夫特 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
}
Updated for Swift 2
为 Swift 2 更新
The code you provide works but doesn't allow you to capture the NavigationBar
and the StatusBar
in your screenshot. If you want to take a screenshot of your device that will include the NavigationBar
, you have to use the following code:
您提供的代码有效,但不允许您在屏幕截图中捕获NavigationBar
和StatusBar
。如果要截取包含 的设备屏幕截图,则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)
}
With this code:
使用此代码:
- The first time you launch the app and call this method, the iOS device will ask you the permission to save your image in the camera roll.
- The result of this code will be a .JPG image.
- The
StatusBar
will not appear in the final image.
- 第一次启动应用程序并调用此方法时,iOS 设备会询问您是否允许将图像保存在相机胶卷中。
- 此代码的结果将是一个 .JPG 图像。
- 将
StatusBar
不会出现在最终图像。
回答by Vasily Bodnarchuk
Details
细节
- Xcode 9.3, Swift 4.1
- Xcode 10.2 (10E125) and 11.0 (11A420a), Swift 5
- Xcode 9.3,斯威夫特 4.1
- Xcode 10.2 (10E125) 和 11.0 (11A420a),Swift 5
Tested on iOS: 9, 10, 11, 12, 13
在 iOS 上测试:9、10、11、12、13
Solution
解决方案
import UIKit
extension UIApplication {
func getKeyWindow() -> UIWindow? {
if #available(iOS 13, *) {
return windows.first { imageView.image = UIApplication.shared.makeSnapshot()
// or
imageView.image = view.makeSnapshot()
// or
imageView.image = view.layer.makeSnapshot()
// or
imageView.image = UIImage(snapshotOf: view)
.isKeyWindow }
} else {
return keyWindow
}
}
func makeSnapshot() -> UIImage? { return getKeyWindow()?.layer.makeSnapshot() }
}
extension CALayer {
func makeSnapshot() -> UIImage? {
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(frame.size, false, scale)
defer { UIGraphicsEndImageContext() }
guard let context = UIGraphicsGetCurrentContext() else { return nil }
render(in: context)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
return screenshot
}
}
extension UIView {
func makeSnapshot() -> UIImage? {
if #available(iOS 10.0, *) {
let renderer = UIGraphicsImageRenderer(size: frame.size)
return renderer.image { _ in drawHierarchy(in: bounds, afterScreenUpdates: true) }
} else {
return layer.makeSnapshot()
}
}
}
extension UIImage {
convenience init?(snapshotOf view: UIView) {
guard let image = view.makeSnapshot(), let cgImage = image.cgImage else { return nil }
self.init(cgImage: cgImage, scale: image.scale, orientation: image.imageOrientation)
}
}
Usage
用法
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
}
}
Old solution
旧解决方案
Xcode 8.2.1, swift 3
Xcode 8.2.1,快速 3
Version 1 for iOS 10x
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
}
}
Version 2 for iOS 9x, 10x
适用于 iOS 9x、10x 的版本 2
If you will try to use Version 1 code in iOS 9xyou will have error: CGImageCreateWithImageProvider: invalid image provider: NULL.
如果您尝试在 iOS 9x 中使用版本 1 代码,则会出现错误:CGImageCreateWithImageProvider: invalid image provider: NULL。
let screenShot = UIApplication.shared.screenShot!
Usage
用法
extension UIImage {
convenience init?(view: UIView?) {
guard let view: UIView = view else { return nil }
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
guard let context: CGContext = UIGraphicsGetCurrentContext() else {
UIGraphicsEndImageContext()
return nil
}
view.layer.render(in: context)
let contextImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard
let image: UIImage = contextImage,
let pngData: Data = image.pngData()
else { return nil }
self.init(data: pngData)
}
}
回答by Daniel Storm
Swift UIImage
extension:
快速UIImage
扩展:
let myImage: UIImage? = UIImage(view: myView)
Usage:
用法:
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
}
}
回答by Damo
For ease I would add an extension in it's own file
为方便起见,我会在它自己的文件中添加一个扩展名
let window: UIWindow! = UIApplication.sharedApplication().keyWindow
let windowImage = window.capture()
call the extension as follows...
拨打分机如下...
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
}
}
Similarly, one could extended UIView to capture an image of that....
类似地,可以扩展 UIView 以捕获该图像的图像....
回答by neave
The recommended way to create a context in iOS 10 is to use UIGraphicsImageRenderer
.
在 iOS 10 中创建上下文的推荐方法是使用UIGraphicsImageRenderer
.
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;
}
回答by diegomen
I use this method:
我用这个方法:
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
}
}]
It captures all but the status bar, and it doesn't ask for permission to save images in the camera roll.
它捕获除状态栏之外的所有内容,并且不要求在相机胶卷中保存图像的权限。
Hope it helps!
希望能帮助到你!
回答by Gregg
Swift 3 Extension for UIWindow
UIWindow 的 Swift 3 扩展
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()
回答by Pung Worathiti Manosroi
This is how I do it in Swift 4
这就是我在 Swift 4 中的做法
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
}
now screenshot will be type UIImage
现在截图将是类型 UIImage
回答by nickcin
Works with Swift 5and iOS 13
适用于Swift 5和iOS 13
For anyone looking for a quick answer for a function to return a screenshot of the viewas a UIImage:
对于任何正在寻找函数的快速答案以将视图的屏幕截图作为 UIImage返回的人:
##代码##I pieced together this answer from taking the code in the question and following David R?nnqvist's suggestions (thank you for the explanation), with some tweaks.
我根据问题中的代码并按照 David R?nnqvist 的建议(感谢您的解释)拼凑了这个答案,并进行了一些调整。
To include the nav bar and other extras, call this method off of the windowinstead of the view.
要包含导航栏和其他附加功能,请在window而不是view 之外调用此方法。
I simply needed a function to get the view's screen capture, so I hope this helps anyone looking for the same
我只需要一个函数来获取视图的屏幕截图,所以我希望这可以帮助任何寻找相同的人