突然ですが、仕事で急遽必要になったためSwiftで簡易PDFビューアーを作りました。
実際はもう少し色々機能があったのですが、「PDFを表示する」という目的に絞ってスリム化しました。
機能としては以下のようなものです。
①初期画面に「PDF表示」のボタンを配置し、クリックすると「PDF閲覧画面」に遷移。
②PDF閲覧画面にてPDFを表示。ページ切り替えは上下のスワイプにて行う。
ネットでpdfを表示するような記事はヒットするんですが、古いものが多かったので一応Swift3に対応しているものとして、参考となれば幸いです。
プロジェクトの作成
まずは新規で「プロジェクト」を作成します。
Xcodeを立ち上げ、「Create a new Xcode project」をクリックします。
次はプロジェクトのタイプを選択します。
「Single View Application」をクリックします。
あとはアプリやデベロッパーの名称、言語、対象デバイスを設定します。今回はiPad向けです。
PDFの表示
下準備が終わったら、次は実際にPDFを表示するロジックを実装していきます。
以下のような構成です。
ViewController.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } |
ViewController.swiftはプロジェクトを作成すると、自動的に生成されます。
今回はViewController.swiftには一切手を加えていません。
PDFShowViewController.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | import UIKit class PDFShowViewController: UIViewController { var pages = 1 var nowPage = 1 var pdfView = PDFView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) let pdfName = ConstStruct.pdf_file_name override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let url = Bundle.main.bundleURL.appendingPathComponent(pdfName) let doc = CGPDFDocument(url as CFURL) pages = doc!.numberOfPages let page = doc!.page(at: nowPage) let myBoundSize: CGSize = UIScreen.main.bounds.size pdfView = PDFView(frame: CGRect(x: 0, y: 0, width: myBoundSize.width, height: myBoundSize.height)) pdfView.backgroundColor = UIColor.white pdfView.page = page self.view.addSubview(pdfView) } //次ページへ @IBAction func downSwiped() { if nowPage < pages { nowPage = nowPage + 1 let url = Bundle.main.bundleURL.appendingPathComponent(pdfName) let doc = CGPDFDocument(url as CFURL) let page = doc!.page(at: nowPage) pdfView.page = page for subview in self.view.subviews { subview.setNeedsDisplay() } } } //前ページへ @IBAction func upSwiped() { if nowPage > 1 { nowPage = nowPage - 1 let url = Bundle.main.bundleURL.appendingPathComponent(pdfName) let doc = CGPDFDocument(url as CFURL) let page = doc!.page(at: nowPage) pdfView.page = page for subview in self.view.subviews { subview.setNeedsDisplay() } } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } |
PDFShowViewController.swiftを追加します。 このクラスでPDFの表示を行います。
下の部分がメインの処理です。
1 2 3 4 5 6 7 8 9 10 11 12 | let url = Bundle.main.bundleURL.appendingPathComponent(pdfName) let doc = CGPDFDocument(url as CFURL) pages = doc!.numberOfPages let page = doc!.page(at: nowPage) let myBoundSize: CGSize = UIScreen.main.bounds.size pdfView = PDFView(frame: CGRect(x: 0, y: 0, width: myBoundSize.width, height: myBoundSize.height)) pdfView.backgroundColor = UIColor.white pdfView.page = page self.view.addSubview(pdfView) |
①PDFファイルの読み込み
②ページ数を読み込んで設定
③PDFViewのインスタンス化
④PDFViewを画面に表示
といった事をやっています。
PDFViewはUIViewを継承したPDFの表示に特化したクラスです。
PDFView.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import UIKit import CoreGraphics class PDFView: UIView { var page: CGPDFPage? override func draw(_ rect: CGRect) { guard let page = page else { return } let context = UIGraphicsGetCurrentContext() context!.translateBy(x: 0, y: rect.size.height) context!.scaleBy(x: 1.0, y: -1.0) let box = page.getBoxRect(.artBox) let xScale = rect.size.width / box.size.width let yScale = rect.size.height / box.size.height let scale = min(xScale, yScale) let tx = (rect.size.width - box.size.width * scale) / 2 let ty = (rect.size.height - box.size.height * scale) / 2 context!.translateBy(x: 0, y: ty) context!.scaleBy(x: scale, y: scale) context!.drawPDFPage(page) } } |
viewに何か描画したい場合はdrawメソッドを呼び出します。 コンテキストを取得して、サイズやスケールなどの設定、最後にdrawPDFPageメソッドにてPDFを表示します。
Define.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import UIKit struct ConstStruct { static let main_color_red: CGFloat = 0.00 static let main_color_green: CGFloat = 0.40 static let main_color_blue: CGFloat = 1.00 static let main_title_color_red: CGFloat = 1.00 static let main_title_color_green: CGFloat = 1.00 static let main_title_color_blue: CGFloat = 1.00 static let pdf_file_name: String = "setsumei.pdf" } class Define{ } |
おまけです。
storyboard
クラスを実装し終わったら、次はstoryboardで画面遷移やアクションなどを定義していきます。
といっても、今回は非常にシンプルなアプリなのでやる事はそれほどないです。
まずは「View Controller」のオブジェクトをstoryboardに配置します。
必要なのはさきほど追加したPDFShowViewController.swiftに対応するオブジェクトです。
配置する対象はMain.storyboardです。
これをドラッグでstoryboard内の適当な場所に置いてやります。
次はそのオブジェクトとPDFShowViewController.swiftを関連付けます。
classにPDFShowViewControllerを指定します。
次はViewControllerからPDFShowViewControllerへの遷移を定義します。
まずはViewControllerにボタンを配置します。さっきの「View Controller」のオブジェクトを配置したのと同じやり方で、今度は「Button」を置いてやります。仮に「PDF表示」としています。
そして、PDFShowViewControllerの上部の一番左のシンボルを右クリックします。
するとメニューが出てきますので、その中の「show」の右端のマルをドラッグして、さきほど追加したView Controllerのボタンに紐づけます。
スワイプのアクションも同じように、スワイプのオブジェクトを「PDFShowViewController」に追加し、アクションを紐づけます。
これでstoryboard上での各種定義は完了です。
動作確認
それでは早速動かしてみましょう。
PDF表示をタップすると、PDFが表示されます。
ソースコードをGitHubにあげていますので、試してみたい方は以下からどうぞ。