ios 如何将 UIView 转换为图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30696307/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:15:30  来源:igfitidea点击:

How to convert a UIView to an image

iosswiftuiviewscreenshot

提问by Sameer Hussain

I want to convert a UIView to an image and save it in my app. Can someone please tell me how to take screenshot of a view or convert it to an image and what is the best way to save it in an app (Not camera roll)? Here is the code for the view:

我想将 UIView 转换为图像并将其保存在我的应用程序中。有人可以告诉我如何截取视图的屏幕截图或将其转换为图像,以及将其保存在应用程序中的最佳方式是什么(不是相机胶卷)?这是视图的代码:

var overView   = UIView(frame: CGRectMake(0, 0, self.view.frame.width/1.3, self.view.frame.height/1.3))
overView.center = CGPointMake(CGRectGetMidX(self.view.bounds),
CGRectGetMidY(self.view.bounds)-self.view.frame.height/16);
overView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(overView)
self.view.bringSubviewToFront(overView)

采纳答案by Sameer Hussain

For example if I have a view of size: 50 50 at 100,100. I can use the following to take a screenshot:

例如,如果我有一个尺寸视图:50 50 at 100,100。我可以使用以下内容截取屏幕截图:

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), false, 0);
    self.view.drawViewHierarchyInRect(CGRectMake(-50,-5-,view.bounds.size.width,view.bounds.size.height), afterScreenUpdates: true)
    var image:UIImage = UIGraphicsGetImageFromCurrentImageContext();

回答by Naveed J.

An extension on UIViewshould do the trick.

扩展UIView应该可以解决问题。

extension UIView {

    // Using a function since `var image` might conflict with an existing variable
    // (like on `UIImageView`)
    func asImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    }
}

Apple discourages using UIGraphicsBeginImageContextstarting iOS 10 with the introduction of the P3 color gamut. UIGraphicsBeginImageContextis sRGB and 32-bit only. They introduced the new UIGraphicsImageRendererAPI that is fully color managed, block-based, has subclasses for PDFs and images, and automatically manages the context lifetime. Check out WWDC16 session 205for more details (image rendering begins around the 11:50 mark)

UIGraphicsBeginImageContext随着 P3 色域的引入,Apple 不鼓励使用启动 iOS 10。UIGraphicsBeginImageContext仅 sRGB 和 32 位。他们引入了新的UIGraphicsImageRendererAPI,该API 是完全颜色管理的、基于块的、具有 PDF 和图像的子类,并自动管理上下文生命周期。查看WWDC16 session 205了解更多细节(图像渲染在 11:50 左右开始)

To be sure that it works on every device, use #availablewith a fallback to earlier versions of iOS:

为确保它适用于所有设备,请使用#available较早版本的 iOS:

extension UIView {

    // Using a function since `var image` might conflict with an existing variable
    // (like on `UIImageView`)
    func asImage() -> UIImage {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: bounds)
            return renderer.image { rendererContext in
                layer.render(in: rendererContext.cgContext)
            }
        } else {
            UIGraphicsBeginImageContext(self.frame.size)
            self.layer.render(in:UIGraphicsGetCurrentContext()!)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return UIImage(cgImage: image!.cgImage!)
        }
    }
}

回答by Bao Tuan Diep

you can use extension

你可以使用扩展

extension UIImage {
    convenience init(view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in:UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: image!.cgImage!)
    }
}

Here the swift 3/4 version :

这里是 swift 3/4 版本:

extension UIImage {
    convenience init(view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in:UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: image!.cgImage!)
    }
}

回答by ViJay Avhad

Convert your UIView to image by drawViewHierarchyInRect:afterScreenUpdates:which is many times faster than renderInContext

通过drawViewHierarchyInRect:afterScreenUpdates:将您的 UIView 转换为图像比 renderInContext 快很多倍

Important note: do not call this function from viewDidLoad or viewWillAppear, make sure you are capturing a view after it is it displayed /loaded fully

重要提示:不要从viewDidLoad 或 viewWillAppear调用此函数,确保在视图完全显示/加载后捕获视图

Obj C

对象C

     UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.opaque, 0.0f);
     [myView drawViewHierarchyInRect:myView.bounds afterScreenUpdates:NO];
     UIImage *snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();

     myImageView.image =  snapshotImageFromMyView;

Save the edited image Photo album

保存编辑好的图片相册

     UIImageWriteToSavedPhotosAlbum(snapshotImageFromMyView, nil,nil, nil);

Swift 3/4

斯威夫特 3/4

    UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.isOpaque, 0.0)
    myView.drawHierarchy(in: myView.bounds, afterScreenUpdates: false)
    let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    print(snapshotImageFromMyView)
    myImageView.image = snapshotImageFromMyView

Super easy generalization with extension , iOS11 , swift3/4

使用扩展、iOS11、swift3/4 进行超级简单的泛化

extension UIImage{
    convenience init(view: UIView) {

    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
    view.drawHierarchy(in: view.bounds, afterScreenUpdates: false)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    self.init(cgImage: (image?.cgImage)!)

  }
}


Use : 
 //myView is completly loaded/visible , calling this code after only after viewDidAppear is call
 imgVV.image = UIImage.init(view: myView)
 // Simple image object
 let img =  UIImage.init(view: myView)

回答by afrodev

On iOS 10:

在 iOS 10 上:

extension UIImage {
    convenience init(view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: (image?.cgImage)!)
    }
}

回答by Jon Willis

Best practice as of iOS 10 and Swift 3

iOS 10 和 Swift 3 的最佳实践

while still supporting iOS 9 and earlierstill works as of iOS 13, Xcode 11.1, Swift 5.1

虽然仍支持 iOS 9 及更早版本,但仍适用于 iOS 13、Xcode 11.1、Swift 5.1

extension UIView {

    func asImage() -> UIImage? {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: bounds)
            return renderer.image { rendererContext in
                layer.render(in: rendererContext.cgContext)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
            defer { UIGraphicsEndImageContext() }
            guard let currentContext = UIGraphicsGetCurrentContext() else {
                return nil
            }
            self.layer.render(in: currentContext)
            return UIGraphicsGetImageFromCurrentImageContext()
        }
    }
}

I am unsure what the question means by:

我不确定这个问题是什么意思:

what is the best way to save it in an app (Not camera roll)?

将它保存在应用程序中的最佳方法是什么(不是相机胶卷)?

回答by Vakas

    UIGraphicsBeginImageContext(self.view.bounds.size);        
    self.view.layer.renderInContext(UIGraphicsGetCurrentContext())
    var screenShot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

回答by Tino

In my opinion, the approach with the initialiser isn't that great because it creates two images.

在我看来,初始化程序的方法并不是那么好,因为它创建了两个图像。

I prefer this:

我更喜欢这个:

extension UIView {
    var snapshot: UIImage? {
        UIGraphicsBeginImageContext(self.frame.size)
        guard let context = UIGraphicsGetCurrentContext() else {
            return nil
        }
        layer.render(in: context)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

回答by Lance Samaria

This works for me for Xcode 9/Swift 3.2/Swift 4and Xcode 8/Swift 3

这对我适用于Xcode 9/Swift 3.2/Swift 4Xcode 8/Swift 3

 if #available(iOS 10.0, *) {

     // for Xcode 9/Swift 3.2/Swift 4 -Paul Hudson's code
     let renderer = UIGraphicsImageRenderer(size: view!.bounds.size)
     let capturedImage = renderer.image { 
         (ctx) in
         view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true)
     }
     return capturedImage

 } else {

     // for Xcode 8/Swift 3
     UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0)
     view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false)
     let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
     UIGraphicsEndImageContext()
     return capturedImage!
 }

Here's how to use it inside a function:

以下是在函数中使用它的方法:

fileprivate func captureUIImageFromUIView(_ view:UIView?) -> UIImage {

     guard (view != nil) else{

        // if the view is nil (it's happened to me) return an alternative image
        let errorImage = UIImage(named: "Error Image")
        return errorImage
     }

     // if the view is all good then convert the image inside the view to a uiimage
     if #available(iOS 10.0, *) {

         let renderer = UIGraphicsImageRenderer(size: view!.bounds.size)
         let capturedImage = renderer.image { 
             (ctx) in
             view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true)
         }
         return capturedImage

     } else {

         UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0)
         view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false)
         let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
         UIGraphicsEndImageContext()
         return capturedImage!
     }
}

Here's how to do something with the image returned from the function:

以下是如何处理从函数返回的图像:

@IBOutlet weak fileprivate var myCustomView: UIView!
var myPic: UIImage?

let myImageView = UIImageView()

@IBAction fileprivate func saveImageButtonTapped(_ sender: UIButton) {

   myPic = captureUIImageFromUIView(myCustomView)

   // display the pic inside a UIImageView
   myImageView.image = myPic!
}

I got the Xcode 9/Swift 3.2/Swift 4answer from Paul Hudson convert uiview to uiimage

我从 Paul Hudson得到了Xcode 9/Swift 3.2/Swift 4 的答案,将 uiview 转换为 uiimage

I got the Xcode 8/Swift 3from somewhere on SO a longgg time ago and I forgot where :(

很久以前,我从 SO 上的某个地方获得了Xcode 8/Swift 3,但我忘记了在哪里:(

回答by Den

Swift 4.2, iOS 10

斯威夫特 4.2,iOS 10

extension UIView {

    // If Swift version is lower than 4.2, 
    // You should change the name. (ex. var renderedImage: UIImage?)

    var image: UIImage? {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) }
    }
}

Sample

样本

let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.backgroundColor = .blue

let view2 = UIView(frame: CGRect(x: 10, y: 10, width: 20, height: 20))
view2.backgroundColor = .red
view.addSubview(view2)

let imageView = UIImageView(image: view.image)

enter image description here

在此处输入图片说明