📜 ⬆️ ⬇️

Create an eBook reader with PDFKit on Swift

Good day! I present to your attention the continuation of the article “Download, save and view PDF in Swift”, as the author promised - we will take a closer look at PDFKit.

PDFKit appeared in iOS 11, and it has 3 great features that I would like to talk about in the process of creating an eBook reader app: Paging, Content Display, and Page Icon .

Everyone who is interested, welcome under cat.

image
')
image

image
Paging, Outline, and Thumbnails

Creating PDFViewController with Initializer Injection

When creating the URL variable in PDFViewController, we made it immutable. That is why I chose Initializer Injection , rather than Property Injection or Method Injection .

The only variable to be injected is pdfUrl , while the others, document and outline , are accessible through the local class area and can be initiated via init () .

The content of pdfView does not change with us, so I marked it with the document variable and also initialized with init () .

import UIKit import PDFKit class PDFViewController: UIViewController { private let pdfUrl: URL private let document: PDFDocument! private let outline: PDFOutline? private var pdfView = PDFView() init(pdfUrl: URL) { self.pdfUrl = pdfUrl self.document = PDFDocument(url: pdfUrl) self.outline = document.outlineRoot pdfView.document = document super.init(nibName: nil, bundle: nil) } ... override func viewDidLoad() { super.viewDidLoad() view.addSubview(pdfView) } } 

 import UIKit class ViewController: UIViewController { @IBAction func openPdfPressed(_ sender: Any) { guard let path = Bundle.main.url(forResource: "swift", withExtension: "pdf") else { print("failed to unwrap fileURL") return } let pdfViewController = PDFViewController(pdfUrl: path) present(pdfViewController, animated: true, completion: nil) } } 

Set horizontal paging

Now we have the content in the document, which we wrote in pdfView.document . In order to make a horizontal scroll, as in the book, you need to add a few settings to PDFView.

 private func setupPDFView() { view.addSubview(pdfView) pdfView.displayDirection = .horizontal pdfView.usePageViewController(true) pdfView.pageBreakMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) pdfView.autoScales = true } 

image

Page icons for easy navigation

PDFKit has an amazingly handy thing, such as ThumbnailView. All you need to do is assign our pdfView property to thumbnailView.pdfView . And that's it! No delegates, notifications and other settings.

 private func setupThumbnailView() { thumbnailView.pdfView = pdfView thumbnailView.backgroundColor = UIColor(displayP3Red: 179/255, green: 179/255, blue: 179/255, alpha: 0.5) thumbnailView.layoutMode = .horizontal thumbnailView.thumbnailSize = CGSize(width: 80, height: 100) thumbnailView.contentInset = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10) view.addSubview(thumbnailView) } 

image

Content display for chapter navigation

To get to a specific page, we need to transfer to pdfView a specific page ( PDFPage ). So we need to delve into the hierarchy of content ( outline ) in the document ( document ) to get to the desired page ( page ).

image

I use UITableViewController as a pop-up window ( popOver ). Therefore, I need to:

  1. Create a protocol. UITableViewController must follow this protocol.
  2. Add some delegate methods to access pdfView in PDFViewController .
  3. Call the delegate method when the user selects a particular cell.

 import UIKit import PDFKit protocol OutlineDelegate: class { func goTo(page: PDFPage) } class OutlineTableViewController: UITableViewController { let outline: PDFOutline weak var delegate: OutlineDelegate? init(outline: PDFOutline, delegate: OutlineDelegate?) { self.outline = outline self.delegate = delegate super.init(nibName: nil, bundle: nil) } ... override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return outline.numberOfChildren } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell if let label = cell.textLabel, let title = outline.child(at: indexPath.row)?.label { label.text = String(title) } return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if let page = outline.child(at: indexPath.row)?.destination?.page { delegate?.goTo(page: page) } } } 

image

Hooray! So we used the 3 main functions of PDFKit. There are some more trivial details of the interface, but in this article we will not focus on them. The project is available under the link for everyone.

Source: https://habr.com/ru/post/431012/


All Articles