Trying to add functionality to be able to air Print a UITableView - ios

I have a (to-do style) list app. the data is laid out in a diffable dataSource tableview with custom cells. I have a functioning dropdown menu and I'm trying to add a print button so the user can print out the list if they'd like (seems standard in a lot of list apps).
So far I have the following in the button's action:
let printController = UIPrintInteractionController.shared
printController.delegate = self
let printInfo = UIPrintInfo(dictionary: nil)
printInfo.outputType = .general
printInfo.jobName = "Print TableView"
printController.printInfo = printInfo
let tableViewPDF = self?.tableView.exportAsPdfFromTable()
printController.printingItem = tableViewPDF
let formatter = UIPrintFormatter()
formatter.perPageContentInsets = UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50)
printController.printFormatter = formatter
printController.present(animated: true, completionHandler: nil)
and the delegate:
extension ListTableViewController: UIPrintInteractionControllerDelegate {
func printInteractionControllerParentViewController(_ printInteractionController: UIPrintInteractionController) -> UIViewController? {
return self
}
}
As you can see I am trying to convert the tableview into a PDF and print that (something else might be better perhaps?). The .exportAsPdfFromTable() method on tableView is a UITableView extension as follows:
extension UITableView {
// Export pdf from UITableView and save pdf in drectory and return pdf file path
func exportAsPdfFromTable() -> String {
let originalBounds = self.bounds
self.bounds = CGRect(x:originalBounds.origin.x, y: originalBounds.origin.y, width: self.contentSize.width, height: self.contentSize.height)
let pdfPageFrame = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.contentSize.height)
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, pdfPageFrame, nil)
UIGraphicsBeginPDFPageWithInfo(pdfPageFrame, nil)
guard let pdfContext = UIGraphicsGetCurrentContext() else { return "" }
self.layer.render(in: pdfContext)
UIGraphicsEndPDFContext()
self.bounds = originalBounds
// Save pdf data
return self.saveTablePdf(data: pdfData)
}
// Save pdf file in document directory
func saveTablePdf(data: NSMutableData) -> String {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docDirectoryPath = paths[0]
let pdfPath = docDirectoryPath.appendingPathComponent("tablePdf.pdf")
if data.write(to: pdfPath, atomically: true) {
return pdfPath.path
} else {
return ""
}
}
}
The result is the print controller being presented with a blank page. Any ideas on what I'm missing?

Related

How i can export WebView to PDF full screen swift iOS

I'm working on webView and there is a challenging part for me capture the full screen depending on webView content.File exported successfully but not capture the whole screen data. Webview screen contains the large data like scrollable content.Can any one guide me how I can export full screen data depending on content.See my code below.
#IBAction func exportPDF(_ sender: UIButton) {
self.webview?.exportAsPdfFromWebView()
}
extension WKWebView {
// Call this function when WKWebView finish loading
func exportAsPdfFromWebView() -> String {
let pdfData = createPdfFile(printFormatter: self.viewPrintFormatter())
return self.saveWebViewPdf(data: pdfData)
}
func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSMutableData {
let originalBounds = self.bounds
self.bounds = CGRect(x: originalBounds.origin.x, y: bounds.origin.y, width: self.bounds.size.width, height: self.scrollView.contentSize.height)
let pdfPageFrame = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.scrollView.contentSize.height)
let printPageRenderer = UIPrintPageRenderer()
printPageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
printPageRenderer.setValue(NSValue(cgRect: UIScreen.main.bounds), forKey: "paperRect")
printPageRenderer.setValue(NSValue(cgRect: pdfPageFrame), forKey: "printableRect")
self.bounds = originalBounds
return printPageRenderer.generatePdfData()
}
// Save pdf file in document directory
func saveWebViewPdf(data: NSMutableData) -> String {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docDirectoryPath = paths[0]
let pdfPath = docDirectoryPath.appendingPathComponent("\(UUID().uuidString).pdf")
if data.write(to: pdfPath, atomically: true) {
return pdfPath.path
} else {
return ""
}
}
}
extension UIPrintPageRenderer {
func generatePdfData() -> NSMutableData {
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil)
self.prepare(forDrawingPages: NSMakeRange(0, self.numberOfPages))
let printRect = UIGraphicsGetPDFContextBounds()
for pdfPage in 0 ..< self.numberOfPages {
UIGraphicsBeginPDFPage()
self.drawPage(at: pdfPage, in: printRect)
}
UIGraphicsEndPDFContext()
return pdfData
}
}

how to add create pdf button at share sheet IOS in swift 5

I open url using uiwebview then I show share sheet, but there is no create pdf button. I want show the create pdf button like safari, and create pdf from url then share the pdf. how to do it?
OR how to create pdf from url webview/uiview then save pdf to files?
this is my share sheet
and this is safari share sheet have create pdf button
and this my code to show share sheet
let items = [URL(string: "https://www.apple.com")!]
let ac = UIActivityViewController(activityItems: items, applicationActivities: nil)
present(ac, animated: true)
extension WKWebView {
// Call this function when WKWebView finish loading
func exportAsPdfFromWebView() -> String {
let pdfData = createPdfFile(printFormatter: self.viewPrintFormatter())
return self.saveWebViewPdf(data: pdfData)
}
func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSMutableData {
let originalBounds = self.bounds
self.bounds = CGRect(x: originalBounds.origin.x,
y: bounds.origin.y,
width: self.bounds.size.width,
height: self.scrollView.contentSize.height)
let pdfPageFrame = CGRect(x: 0, y: 0, width: self.bounds.size.width,
height: self.scrollView.contentSize.height)
let printPageRenderer = UIPrintPageRenderer()
printPageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
printPageRenderer.setValue(NSValue(cgRect: UIScreen.main.bounds), forKey: "paperRect")
printPageRenderer.setValue(NSValue(cgRect: pdfPageFrame), forKey: "printableRect")
self.bounds = originalBounds
return printPageRenderer.generatePdfData()
}
// Save pdf file in document directory
func saveWebViewPdf(data: NSMutableData) -> String {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docDirectoryPath = paths[0]
let pdfPath = docDirectoryPath.appendingPathComponent("webViewPdf.pdf")
if data.write(to: pdfPath, atomically: true) {
return pdfPath.path
} else {
return ""
}
}
}
extension UIPrintPageRenderer {
func generatePdfData() -> NSMutableData {
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil)
self.prepare(forDrawingPages: NSMakeRange(0, self.numberOfPages))
let printRect = UIGraphicsGetPDFContextBounds()
for pdfPage in 0..<self.numberOfPages {
UIGraphicsBeginPDFPage()
self.drawPage(at: pdfPage, in: printRect)
}
UIGraphicsEndPDFContext();
return pdfData
}
}
You can create pdf from url webview/uiview then save pdf to files using this
I found the answer from other
first I create new class PDF.swift
class func generate(using printFormatter: UIPrintFormatter) -> String {
// assign the print formatter to the print page renderer
let renderer = UIPrintPageRenderer()
renderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
// static let ANSI_A = CGSize(width:612,height:792)
// static let ANSI_B = CGSize(width:792,height:1224)
// static let ANSI_C = CGSize(width:1584,height:1224)
// static let ANSI_D = CGSize(width:2448,height:1584)
// static let ANSI_E = CGSize(width:3168,height:2448)
//
// static let ISO216_A0 = CGSize(width:2384,height:3370)
// static let ISO216_A1 = CGSize(width:1684,height:2384)
// static let ISO216_A2 = CGSize(width:1190,height:1684)
// static let ISO216_A3 = CGSize(width:842,height:1190)
// static let ISO216_A4 = CGSize(width:595,height:842)
// static let ISO216_A5 = CGSize(width:420,height:595)
// static let ISO216_A6 = CGSize(width:298,height:420)
// static let ISO216_A7 = CGSize(width:210,height:298)
// static let ISO216_A8 = CGSize(width:148,height:210)
// assign paperRect and printableRect values
let page = CGRect(x: 0, y: 0, width: 1190, height: 842) // A3 landscape
// let page = CGRect(x: 0, y: 0, width: 2384, height: 800) // A4, 72 dpi
renderer.setValue(page, forKey: "paperRect")
renderer.setValue(page, forKey: "printableRect")
// create pdf context and draw each page
let pdfData = NSMutableData()
// UIGraphicsBeginPDFContextToData(pdfData, .zero, nil)
UIGraphicsBeginPDFContextToData(pdfData, page, nil)
for i in 0..<renderer.numberOfPages {
UIGraphicsBeginPDFPage()
renderer.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext();
// save data to a pdf file and return
guard nil != (try? pdfData.write(to: outputURL, options: .atomic))
else { fatalError("Error writing PDF data to file.") }
return outputURL.absoluteString
}
private class var outputURL: URL {
guard let directory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
else { fatalError("Error getting user's document directory.") }
let url = directory.appendingPathComponent(outputFileName).appendingPathExtension("pdf")
print("open \(url.path)")
return url
}
private class var outputFileName: String {
return "generated-\(Int(Date().timeIntervalSince1970))"
}
and call the function to generate pdf then share using share sheet to save files
let uiPDFData = PDF.generate(using: self.uiWebViewPrintFormatter())
print(uiPDFData)
DispatchQueue.main.async{
let fileURL = NSURL(fileURLWithPath: (uiPDFData))
// Create the Array which includes the files you want to share
var filesToShare = [Any]()
// Add the path of the file to the Array
filesToShare.append(fileURL)
// Make the activityViewContoller which shows the share-view
let activityViewController = UIActivityViewController(activityItems: filesToShare, applicationActivities: nil)
// Show the share-view
if UIDevice.current.userInterfaceIdiom == .pad {
if let popup = activityViewController.popoverPresentationController {
popup.sourceView = self.view
popup.sourceRect = CGRect(x: self.view.frame.size.width / 2, y: self.view.frame.size.height / 4, width: 0, height: 0)
}
}
self.present(activityViewController, animated: true, completion: nil)
}

pdf from tableview with 100 cells

I am using below code to generate pdf from my tableview , but it generates pdf from visible cells only.
how to generate pdf from complete tableview
eg : Visible cells
cell1
cell2
.
.
.
.
.
cell10
non visible cell to current view
cell11
cell12
.
.
.
.
cell20
on generating pdf it only create pdf of visible cells
I need to create all tableview cell1 to cell20 in pdf.
extension UITableView {
// Export pdf from UITableView and save pdf in drectory and return pdf file path
func exportAsPdfFromTable() -> String {
let originalBounds = self.bounds
self.bounds = CGRect(x:originalBounds.origin.x, y: originalBounds.origin.y, width: self.contentSize.width, height: self.contentSize.height)
let pdfPageFrame = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.contentSize.height)
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, pdfPageFrame, nil)
UIGraphicsBeginPDFPageWithInfo(pdfPageFrame, nil)
guard let pdfContext = UIGraphicsGetCurrentContext() else { return "" }
self.layer.render(in: pdfContext)
UIGraphicsEndPDFContext()
self.bounds = originalBounds
// Save pdf data
return self.saveTablePdf(data: pdfData)
}
// Save pdf file in document directory
func saveTablePdf(data: NSMutableData) -> String {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docDirectoryPath = paths[0]
let pdfPath = docDirectoryPath.appendingPathComponent("tablePdf.pdf")
if data.write(to: pdfPath, atomically: true) {
return pdfPath.path
} else {
return ""
}
}
}
to use it
let pdfFilePath = self.tableView.exportAsPdfFromTable()
print(pdfFilePath)

How do I generate a PDF containing views with dimensions larger than device screen?

I have several UIViews with clear background color, and black border outlines that all resize based on values I enter in length, width, and height text fields. These views are subviews of a UIScrollView. After the views resize I create a PDF from the contents of the scroll view resulting in vectorized outlines that I can use and manipulate in Adobe Illustrator.
This process works fine when I use small dimensions for the views (i.e. 15 x 15), but when I use more ideal dimensions for my purpose (i.e. 3000 x 3000) the views extend off the bounds of the screen and the resulting PDF generated contains only a small portion of the views.
Ideally I need to be able to create much larger views and still be able to generate a PDF containing them. I'm envisioning a canvas that resizes (zooms out?) based on its contents and retains the scale of its subviews so that the resulting views in the PDF will be to-scale when viewed in Adobe Illustrator. This is my code so far:
override func viewDidLoad() {
super.viewDidLoad()
lengthTextField.delegate = self
widthTextField.delegate = self
heightTextField.delegate = self
scrollView.delegate = self
scrollView.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth,UIView.AutoresizingMask.flexibleHeight]
scrollView.minimumZoomScale = 1
scrollView.maximumZoomScale = 50
scrollView.zoomScale = 1
self.setupGestureRecognizer()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: 5000, height: 5000)
}
func setupGestureRecognizer() {
}
#IBAction func viewPDF(_ sender: Any) {
createPDFfrom(aView: self.scrollView.subviews[0], saveToDocumentsWithFileName: "MC.pdf")
// Create and add a PDFView to the view hierarchy.
let pdfView = PDFView(frame: self.scrollView.subviews[0].bounds)
pdfView.autoScales = true
view.addSubview(pdfView)
// Create a PDFDocument object and set it as PDFView's document to load the document in that view.
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath = (documentsDirectory as NSString).appendingPathComponent("MC.pdf") as String
let pdfDocument = PDFDocument(url: URL(fileURLWithPath: filePath))!
pdfView.document = pdfDocument
let document = NSData(contentsOfFile: filePath)
let vc = UIActivityViewController(activityItems: [document as Any], applicationActivities: nil)
self.present(vc, animated: true, completion: nil)
}
func createPDFfrom(aView: UIView, saveToDocumentsWithFileName fileName: String)
{
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil)
UIGraphicsBeginPDFPage()
guard let pdfContext = UIGraphicsGetCurrentContext() else { return }
aView.layer.render(in: pdfContext)
UIGraphicsEndPDFContext()
if let documentDirectories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
let documentsFileName = documentDirectories + "/" + fileName
debugPrint(documentsFileName)
pdfData.write(toFile: documentsFileName, atomically: true)
}
}
#IBAction func updateDimensions(_ sender: Any) {
guard let length = NumberFormatter().number(from:
lengthTextField.text ?? "") else { return }
guard let width = NumberFormatter().number(from:
widthTextField.text ?? "") else { return }
guard let height = NumberFormatter().number(from:
heightTextField.text ?? "") else { return }
let flapHeight = CGFloat(truncating: width)/2
let lengthFloat = CGFloat(truncating: length)
let widthFloat = CGFloat(truncating: width)
let heightFloat = CGFloat(truncating: height)
UIView.animate(withDuration: 0.3) {
self.faceAWidthConstraint.constant = lengthFloat
self.faceAHeightConstraint.constant = heightFloat
self.faceBWidthConstraint.constant = widthFloat
self.faceA1HeightConstraint.constant = flapHeight
self.view.layoutIfNeeded()
}
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return scrollView.subviews[0]
}
}
I think if you use UIGraphicsPDFRenderer this might work better:
let url = URL(fileURLWithPath: filePath)
let pdfGenerator = UIGraphicsPDFRenderer(bounds: .init(x: 0, y: 0, width: 612, height: 792))
pdfGenerator.writePDF(to: url) { context in
let cgContext = context.cgContext
aView.layer.render(in: cgContext)
}
If the views are still extending outside of the PDF's bounds then you could scale the context:
cgContext.scaleBy(x: 0.25, y:0.25)

Create pdf of tableview all data

I have create pdf of tableview all cells. but i have create the pdf it does not show all data of tableview & also when pdf page height set according to cells data. I dont know how to resolve this issue. I am using this code for create pdf.please help me.
let _: NSData!
do {
let priorBounds = table_view.bounds
let fittedSize = table_view.sizeThatFits(CGSizeMake(priorBounds.size.width, .infinity))
table_view.bounds = CGRectMake(0, 0, fittedSize.width, fittedSize.height)
let pdfPageBounds = CGRectMake(0, 0, 612, 800)
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, pdfPageBounds, nil)
do {
var pageOriginY = 0
while pageOriginY < Int(fittedSize.height) {
UIGraphicsBeginPDFPageWithInfo(pdfPageBounds, nil)
CGContextSaveGState(UIGraphicsGetCurrentContext()!)
do {
CGContextTranslateCTM(UIGraphicsGetCurrentContext()!, 0, -CGFloat(pageOriginY))
table_view.layer.renderInContext(UIGraphicsGetCurrentContext()!)
}
CGContextRestoreGState(UIGraphicsGetCurrentContext()!)
pageOriginY += Int(pdfPageBounds.size.height)
}
}
UIGraphicsEndPDFContext()
table_view.bounds = priorBounds
if let documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first {
let documentsFileName = documentDirectories + "/" + (filename as String)
debugPrint(documentsFileName)
pdfData.writeToFile(documentsFileName, atomically: true)
}
}
Try this.
func createPdfFromTableView()
{
let priorBounds: CGRect = self.tblView.bounds
let fittedSize: CGSize = self.tblView.sizeThatFits(CGSize(width: priorBounds.size.width, height: self.tblView.contentSize.height))
self.tblView.bounds = CGRect(x: 0, y: 0, width: fittedSize.width, height: fittedSize.height)
self.tblView.reloadData()
let pdfPageBounds: CGRect = CGRect(x: 0, y: 0, width: fittedSize.width, height: (fittedSize.height))
let pdfData: NSMutableData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, pdfPageBounds, nil)
UIGraphicsBeginPDFPageWithInfo(pdfPageBounds, nil)
self.tblView.layer.render(in: UIGraphicsGetCurrentContext()!)
UIGraphicsEndPDFContext()
let documentDirectories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let documentsFileName = documentDirectories! + "/" + "pdfName"
pdfData.write(toFile: documentsFileName, atomically: true)
print(documentsFileName)
}
One addition to Rajeskumar's answer below is as follows:
If your UITableView does not occupy the entire device screen with its original bounds, you might want to insert the following line:
self.tblview.bounds = priorBounds
after the render(in:) step. Otherwise, the table will be drawn on the device in a manner in which it will cover more space that originally intended.
Above answers did not work for creating PDF after tableview is scrolled at the bottom.
While reloading tableview(reloadData()) after scrolling, correct PDF is not generated and removing, it won't generate PDF for unloaded items.
So I have added extra condition and refactored as below:
extension UITableView {
func convertToPDF() -> Data? {
let priorBounds = self.bounds
setBoundsForAllItems()
self.layoutIfNeeded()
let pdfData = createPDF()
self.bounds = priorBounds
return pdfData.copy() as? Data
}
private func getContentFrame() -> CGRect {
return CGRect(x: 0, y: 0, width: self.contentSize.width, height: self.contentSize.height)
}
private func createPDF() -> NSMutableData {
let pdfPageBounds: CGRect = getContentFrame()
let pdfData: NSMutableData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, pdfPageBounds, nil)
UIGraphicsBeginPDFPageWithInfo(pdfPageBounds, nil)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
UIGraphicsEndPDFContext()
return pdfData
}
private func setBoundsForAllItems() {
if self.isEndOfTheScroll() {
self.bounds = getContentFrame()
} else {
self.bounds = getContentFrame()
self.reloadData()
}
}
private func isEndOfTheScroll() -> Bool {
let contentYoffset = contentOffset.y
let distanceFromBottom = contentSize.height - contentYoffset
return distanceFromBottom < frame.size.height
}
}
Create PDF of tableview using this way
#IBAction func onClickBtnGeneratePDF(_ sender: Any) {
if enterPDFNAME.text?.isEmpty() == true{
Utility.showToast(message: "Please Enter PDF name")
}else{
self.viewOverlaySavePDF.isHidden = true
Utility.showLoading()
let pdfFilePath = tableview.exportAsPdfFromTable(pdfName: enterPDFNAME.text!)
if pdfFilePath != nil {
self.enterPDFNAME.text = ""
Utility.showToast(message: "Your PDF file saved")
Utility.hideLoading()
}
print(pdfFilePath)
}
}
}
extension UITableView {
// Export pdf from UITableView and save pdf in drectory and return pdf file path
func exportAsPdfFromTable(pdfName:String) -> String {
/* let html = "<b>Hello <i>World!</i></b> <p>Generate PDF file from HTML in Swift</p>"
let fmt = UIMarkupTextPrintFormatter(markupText: html)
// 2. Assign print formatter to UIPrintPageRenderer
let render = UIPrintPageRenderer()
render.addPrintFormatter(fmt, startingAtPageAt: 0)
// 3. Assign paperRect and printableRect
let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4, 72 dpi
let printable = page.insetBy(dx: 0, dy: 0)
render.setValue(NSValue(cgRect: page), forKey: "paperRect")
render.setValue(NSValue(cgRect: printable), forKey: "printableRect")
// 4. Create PDF context and draw
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, .zero, nil)
for i in 1...render.numberOfPages {
UIGraphicsBeginPDFPage();
let bounds = UIGraphicsGetPDFContextBounds()
render.drawPage(at: i - 1, in: bounds)
}
UIGraphicsEndPDFContext();
*/
let originalBounds = self.bounds
self.bounds = CGRect(x:originalBounds.origin.x, y: originalBounds.origin.y, width: self.contentSize.width, height: self.contentSize.height)
let pdfPageFrame = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.contentSize.height)
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, pdfPageFrame, nil)
UIGraphicsBeginPDFPageWithInfo(pdfPageFrame, nil)
guard let pdfContext = UIGraphicsGetCurrentContext() else { return "" }
self.layer.render(in: pdfContext)
UIGraphicsEndPDFContext()
self.bounds = originalBounds
// Save pdf data
return self.saveTablePdf(data: pdfData,name:pdfName)
}
// Save pdf file in document directory
func saveTablePdf(data: NSMutableData,name:String) -> String {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docDirectoryPath = paths[0]
let pdfPath = docDirectoryPath.appendingPathComponent("\(name).pdf")
if data.write(to: pdfPath, atomically: true) {
return pdfPath.path
} else {
return ""
}
}
}
Only one solution for exporting all tableView items: make snapshot of every part of tableview as an image -> merge them into an imageView -> render imageView to pdf.
NOTE: It's the same way with UIScrollView & UICollectionView
func exportPDF() {
// 1. estimate tableview contentsize
UIGraphicsBeginImageContextWithOptions(tableView.contentSize, false, 0)
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
tableView.layer.render(in: UIGraphicsGetCurrentContext()!)
// 2. calculate number of part of tableview, loop and get snapshot
let iterationCount = Int(ceil(tableView.contentSize.height / tableView.bounds.size.height))
for i in 0..<iterationCount {
tableView.setContentOffset(CGPoint(x: 0, y: Int(tableView.bounds.size.height) * i), animated: false)
tableView.layer.render(in: UIGraphicsGetCurrentContext()!)
}
// 3. merge and make UIImageView from snapshot
let image = UIGraphicsGetImageFromCurrentImageContext()
let pdfImageView = UIImageView(image: image)
//4. render imageView to PDF
let pdfData: NSMutableData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, pdfImageView.bounds, nil)
UIGraphicsBeginPDFPageWithInfo(pdfImageView.bounds, nil)
pdfImageView.layer.render(in: UIGraphicsGetCurrentContext()!)
UIGraphicsEndPDFContext()
let documentDirectories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let documentsFileName = documentDirectories! + "/" + "MyPDF.pdf"
pdfData.write(toFile: documentsFileName, atomically: true)
// 5. We have pdf file at documentsFileName
}

Resources