Я хочу преобразовать 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)
ios
swift
uiview
screenshot
Самир Хуссейн
источник
источник
Ответы:
Расширение
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 не рекомендует
UIGraphicsBeginImageContext
запускать iOS 10 с введением цветовой гаммы P3.UIGraphicsBeginImageContext
только sRGB и 32-бит. Они представили новыйUIGraphicsImageRenderer
API, который полностью управляется цветом, основан на блоках, имеет подклассы для PDF-файлов и изображений и автоматически управляет временем существования контекста. Ознакомьтесь с сеансом 205 WWDC16 для получения более подробной информации (рендеринг изображения начинается примерно с 11:50).Чтобы убедиться, что он работает на всех устройствах, используйте
#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!) } } }
источник
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)); view.backgroundColor = .black; view.layer.cornerRadius = 9; view.asImage();
вы можете использовать расширение
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!) } }
источник
let image = UIImage(view: myView)
UIGraphicsBeginImageContextWithOptions(view.frame.size, false, UIScreen.main.scale)
Преобразуйте свой UIView в изображение с помощью drawViewHierarchyInRect: 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/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
Супер простое обобщение с расширением, 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)
источник
В 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)!) } }
источник
Лучшая практика для iOS 10 и Swift 3
хотя все еще поддерживает 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() } } }
Я не уверен, что означает вопрос:
источник
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();
источник
На мой взгляд, подход с инициализатором не так хорош, потому что он создает два изображения.
Я предпочитаю это:
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 } }
источник
Swift 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) } } }
Образец
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)
источник
Это работает для меня для Xcode 9 / Swift 3.2 / Swift 4 и Xcode 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! var myPic: UIImage? let myImageView = UIImageView() @IBAction fileprivate func saveImageButtonTapped(_ sender: UIButton) { myPic = captureUIImageFromUIView(myCustomView) // display the pic inside a UIImageView myImageView.image = myPic! }
Я получил ответ Xcode 9 / Swift 3.2 / Swift 4 от Пола Хадсона преобразовав uiview в uiimage
Я получил Xcode 8 / Swift 3 откуда-то на ТАК давным-давно, и я забыл где :(
источник
var snapshot = overView.snapshotViewAfterScreenUpdates(false)
или в objective-c
UIView* snapshot = [overView snapshotViewAfterScreenUpdates:NO];
источник
Вы можете легко использовать это расширение, подобное этому
// 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)
Если вы хотите использовать эти методы / переменные расширения, реализуйте это
Расширение UIImage
extension UIImage { convenience init(view: UIView) { if let cgImage = view.snapshot?.cgImage { self.init(cgImage: cgImage) } else { self.init() } } }
Расширение 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 } }
Расширение UIApplication
extension UIApplication { var snapshot: UIImage? { return keyWindow?.rootViewController?.view.snapshot } }
источник
или 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) } } }
источник
Спасибо, @Bao Tuan Diep! Я хочу добавить добавку.
Когда вы используете код:
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
раньшеyourView.layer.render(in:UIGraphicsGetCurrentContext()!)
.В противном случае вы можете получить объект изображения, не содержащий элементов.
источник
Swift 4.2
import Foundation import UIKit 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)!) } }
источник
Реализация в 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. вот так, и он сработал.
Вот его размах:
Вот как я это реализовал.
//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()
источник
Инициализатор с новым UIGraphicsImageRenderer, доступным с iOS 10:
extension UIImage{ convenience init(view: UIView) { let renderer = UIGraphicsImageRenderer(size: self.bounds.size) let canvas = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height) let image = renderer.image { _ in self.drawHierarchy(in: canvas, afterScreenUpdates: false) } self.init(cgImage: (image?.cgImage)!) } }
источник
у меня отлично работает!
Swift4
extension UIView { func toImage() -> UIImage { UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0) self.drawHierarchy(in: self.bounds, afterScreenUpdates: false) let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return snapshotImageFromMyView! } }
источник
return snapshotImageFromMyView!
Поток 1: Неустранимая ошибка: Неожиданно обнаружено nil при развертывании необязательного значенияПоскольку представление содержит размытое представление (например, экземпляр UIVisualEffectView ), работает только drawViewHierarchyInRect: afterScreenUpdates .
Ответ @ViJay Avhad верен для этого случая.
источник
Использование UIGraphicsImageRenderer не работает, если представление содержит подвиды Scene Kit, Metal или Sprite Kit. В этих случаях используйте
let renderer = UIGraphicsImageRenderer(size: view.bounds.size) let image = renderer.image { ctx in view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) }
источник
please try below code. -(UIImage *)getMainImageFromContext { UIGraphicsBeginImageContextWithOptions(viewBG.bounds.size, viewBG.opaque, 0.0); [viewBG.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; }
источник