如何将UIView转换为图像

我想将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) 

你可以使用扩展

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

这里快速的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!) } } 

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

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

Obj C

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

保存编辑后的图片相册

  UIImageWriteToSavedPhotosAlbum(snapshotImageFromMyView, nil,nil, nil); 

Swift 3

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

超级简单泛化与扩展,iOS10,Swift3

 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) 

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) } } } 

苹果劝阻使用UIGraphicsBeginImageContext从iOS 10开始,并引入P3色域。 UIGraphicsBeginImageContext只有sRGB和32位。 他们介绍了全新的UIGraphicsImageRenderer API,它是完全由色彩pipe理的,基于块的,具有PDF和图像的子类,并自动pipe理上下文生存期。 查看WWDC16会话205获取更多细节(图像渲染在11:50分左右开始)

在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)!) } } 
  UIGraphicsBeginImageContext(self.view.bounds.size); self.view.layer.renderInContext(UIGraphicsGetCurrentContext()) var screenShot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); 

例如,如果我有一个大小的观点:50 50 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(); 

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

我更喜欢这个:

 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 } } 

截至iOS 10和Swift 3的最佳实践

同时还支持iOS 9及更早版本

 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() } } } 

我不确定这个问题意味着什么:

什么是最好的方式来保存在一个应用程序(不相机胶卷)?

 var snapshot = overView.snapshotViewAfterScreenUpdates(false) 

或者在Objective-C中

 UIView* snapshot = [overView snapshotViewAfterScreenUpdates:NO]; 

这适用于我的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! } 

以下是如何在一个函数中使用它:

 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! } } 

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

 @IBOutlet weak fileprivate var myCustomView: UIView! fileprivate var myPic: UIImage? @IBAction fileprivate func saveImageButtonTapped(_ sender: UIButton) { myPic = captureUIImageFromUIView(myCustomView) //safely unwrap myPic and do something with it } 

我得到了保罗·哈德森的Xcode 9 / Swift 3.2 / Swift 4的答案在uiview中将图像转换为uiimage

我从某个地方得到了Xcode 8 / Swift 3 ,所以我忘记了在哪里:(

或iOS 10或更高版本,您可以使用新的UIGraphicsImageRenderer +推荐的drawHierarchy,在某些情况下,它可能比layer.renderInContext

 extension UIView { func asImage() -> UIImage { let renderer = UIGraphicsImageRenderer(size: self.bounds.size) return renderer.image { _ in self.drawHierarchy(in: CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height), afterScreenUpdates: false) } } } 

您可以使用这样的扩展名轻松使用它

 // Take a snapshot from a view (just one view) let viewSnapshot = myView.snapshot // Take a screenshot (with every views in screen) let screenSnapshot = UIApplication.shared.snapshot // Take a snapshot from UIImage initialization UIImage(view: self.view) 

如果你想使用这些扩展方法/variables,实现这一点

  1. UIImage扩展

     extension UIImage { convenience init(view: UIView) { if let cgImage = view.snapshot?.cgImage { self.init(cgImage: cgImage) } else { self.init() } } } 
  2. UIView扩展

     extension UIView { var snapshot: UIImage? { UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0.0) if UIGraphicsGetCurrentContext() != nil { drawHierarchy(in: bounds, afterScreenUpdates: true) let screenshot = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return screenshot } return nil } } 
  3. UIApplication扩展

     extension UIApplication { var snapshot: UIImage? { return keyWindow?.rootViewController?.view.snapshot } } 

Swift 3中的实现:

添加以下代码,超出课程范围。

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

用法:

 let image = UIImage( Your_View_Outlet ) 

我实现了@Naveed J.的方法,就像魅力一样。

这是他的扩展:

 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) } } } 

这是我如何实现它。

 //create an image from yourView to display //determine the frame of the view/imageimage let screen = self.superview!.bounds let width = screen.width / 4 //make image 1/4 width of screen let height = width let frame = CGRect(x: 0, y: 0, width: width, height: height) let x = (screen.size.width - frame.size.width) * 0.5 let y = (screen.size.height - frame.size.height) * 0.5 let mainFrame = CGRect(x: x, y: y, width: frame.size.width, height: frame.size.height) let yourView = YourView() //instantiate yourView yourView.frame = mainFrame //give it the frame yourView.setNeedsDisplay() //tell it to display (I am not 100% sure this is needed) let characterViewImage = yourView.asImage() 

谢谢@包团团员! 我想添加一个补充。

当你使用的代码:

 yourView.layer.render(in:UIGraphicsGetCurrentContext()!) 

你必须注意到:

  - If you had used `autoLayout` or `Masonry` in `yourView` (that you want to convert) . - If you did not add `yourView` to another view which means that `yourView` was not used as a subview but just an object. 

那么,你必须使用

 [yourView setNeedsLayout]; [yourView layoutIfNeeded]; 

yourView.layer.render(in:UIGraphicsGetCurrentContext()!)之前更新yourView

否则,你可能会得到一个不包含元素的图像对象

 please try below code. -(UIImage *)getMainImageFromContext { UIGraphicsBeginImageContextWithOptions(viewBG.bounds.size, viewBG.opaque, 0.0); [viewBG.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; }