8

I would like to create a PDF from a UITableView in Swift. Ill found some tutorials for Objective C, and tried it out but there is still no file generated by this code.

        // get a temprorary filename for this PDF

        var path = NSTemporaryDirectory();
        var pdfFilePath = path.stringByAppendingPathComponent("mypdfdocument.pdf")

        UIGraphicsBeginPDFContextToFile(pdfFilePath, CGRectMake(0, 0, self.tableView.contentSize.width, self.tableView.contentSize.height), nil)
        UIGraphicsBeginPDFPage();
        self.view.layer.renderInContext(UIGraphicsGetCurrentContext())
        self.tableView.scrollRectToVisible(CGRectMake(0, 0, 1, 1), animated: false)
        self.tableView.layer.renderInContext(UIGraphicsGetCurrentContext())

        var screensInTable = Int(self.tableView.contentSize.width) / Int(self.tableView.contentSize.height)

        for i in 1...screensInTable {

            var point = CGFloat(CGFloat(i) * self.tableView.bounds.height)
            var contentOffset:CGPoint = CGPointMake(0, point)
            self.tableView.setContentOffset(contentOffset, animated: false)
            self.tableView.layer.renderInContext(UIGraphicsGetCurrentContext())
        }

        UIGraphicsEndPDFContext();

And: I have a Table with 4 Sections and different Row Heights and Cell Templates. Is there a Chance that the generated PDF easily with this type of code? Or would it be better to create Row by Row with CoreText?

Thanks in advance.

derdida
  • 14,784
  • 16
  • 90
  • 139

1 Answers1

9

Here is my approach. Use a template view. It has all the static texts and images. And then for every page in pdf use this template view. Here is the function that I use:

func renderAsPDF(demandEntry: ParsedDemandEntry, inView view: UIView) -> NSData? {
    let entries = demandEntry.demands
    let pageCount = Int(ceil(Double(entries.count) / Double(demandCountForPage)))
    if pageCount != 0 {
        let views = (1...pageCount).map { (pageNumber: Int) -> UIView in
            let pdfPageView = createTemplatePageViewWithParsedEntry(demandEntry, inView: view)

            let pageRange = ((pageNumber - 1) * demandCountForPage)..<(min(pageNumber * demandCountForPage, entries.count))
            let entriesForPage = Array(entries[pageRange])

            addEntries(entriesForPage, toView: pdfPageView)

            pdfPageView.removeFromSuperview()

            return pdfPageView
        }

        return toPDF(views)
    } else {
        return nil
    }
}

The ParsedDemandEntry is my model object. The view parameter is a container view to prepare pdf view in it. This is necessary because I use auto layout to position all labels in pdf view. Without a super view layout process won't work.

Let's walk into function. First I get entries from model object. Think these are rows that needs to populate in pdf. After that I calculate how many pages I need. Then the loop begins. In every loop I create a tamplate view. (pdfPageView). And then fill it with entries. (addEntries(_:toView:) function call).

After the loop I give all views to toPDF function. It creates NSData that represents pdf. Here is how toPDF function look like:

private func toPDF(views: [UIView]) -> NSData? {

    if views.isEmpty {
        return nil
    }

    let pdfData = NSMutableData()
    UIGraphicsBeginPDFContextToData(pdfData, CGRect(x: 0, y: 0, width: 612, height: 792), nil)

    let context = UIGraphicsGetCurrentContext()

    for view in views {
        UIGraphicsBeginPDFPage()
        view.layer.renderInContext(context)
    }

    UIGraphicsEndPDFContext()

    return pdfData
}

It is fairly simple. First I create pdf context. And then loop through views array. For each view It renders view into pdf context.

I hope this will help.

mustafa
  • 15,254
  • 10
  • 48
  • 57
  • Thank you for your answer. I am not sure how i could use a "template" View? - i have 9 different Cell Layouts here, so i need to create a View (for all of my cells?) and populate them with my data? – derdida Nov 08 '14 at 15:47
  • 1
    Can you elaborate on what happens in ´createTemplatePageViewWithParsedEntry´? What view do you insert the model into, and how is that view handled? – Wiingaard Nov 06 '16 at 22:31
  • It creates a UIView that represents your pdf page. @Rapsefar – mustafa Nov 07 '16 at 07:06
  • Okay. And adds it as a subview to the `view` that it takes as a parameter? – Wiingaard Nov 07 '16 at 10:05