TL;DR
- PDFKitのサンプルをSwiftUIで作成しました
- ページをめくるたびに今表示されているPDFのページ番号を取得します
- で、NotificatonCenterにaddObserveしてPDFViewからページ番号は取得します
- で、その場合ViewController時代ならViewDidLoadなどで登録したりできますが、どうしたらいいんだろう、、、
と言うあたりを解説します。
デモ
ソースはこちら>https://github.com/dropcontrol/PDFViewer
Viewの解説から
struct ContentView: View {
@ObservedObject var pdfInfo: PDFInfo = PDFInfo()
var body: some View {
VStack {
ShowPDFView(pdfInfo: pdfInfo)
PdfInfoView(pdfInfo: pdfInfo)
.padding()
}.onAppear(){
pdfInfo.addObserver()
}
}
}
一番親になるViewでは二つのViewを呼んでいます。一つはPDFのビュワー部分であるShowPDFView()
で、もう一つはその下でページ番号とTOPボタンを表示してるPdfInfoView()
です。で、そこでpdfInfo: pdfInfo
を渡していますが、それはViewの上の
@ObservedObject var pdfInfo: PDFInfo = PDFInfo()
の部分で@ObservedObject
でObservableObject
であるPDFInfo()
のインスタンスを作成しています。で、そのPDFInfo()
は、、、
class PDFInfo: ObservableObject {
@Published var pageNo: Int = 1
@Published var pdfView: PDFView = PDFView()
@Published var stateTopButton: Bool = false
func addObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(self.pageChanged(_:)), name: Notification.Name.PDFViewPageChanged, object: nil)
}
@objc func pageChanged(_ notification: Notification) {
pageNo = pdfView.currentPage!.pageRef!.pageNumber
stateTopButton = pdfView.canGoToFirstPage
print(self.pageNo)
print("page is changed")
}
}
こんな感じになってます。@Publised
ではpageNo
, pdfView
, stateTopButton
といった変数を作っています。その下ではNotificasionCenterへの登録をするfunc addObserver(){}
を、notificationを受け取ったら実行される@objc func pageChanged(_ notification: Notification) {}
の関数を定義しています。その中ではページ番号と、PDFのトップページかどうかを判断するcanGoToFirstPage
です。
で、このなかでPDFの表示のために必要な、
@Published var pdfView: PDFView = PDFView()
を作っています。なので、先の@ObservedObject
で初期化しています。と言うのもpdfInfo
を他のView
でも使い回したいので、pdfInfo
を読み込んでいるView
に渡しています。
その他のViewについて
PdfInfoView
はUIのところなのでソース読めばわかると思うので割愛して、ShowPDFView
を解説します。ここでは以下のような感じです。
struct ShowPDFView: View {
@ObservedObject var pdfInfo: PDFInfo
var body: some View {
PDFViewer(pdfInfo: pdfInfo)
}
}
ここで用意してる@ObservedObject var pdfInfo: PDFInfo
に親からpdfInfo
を渡しています。@ObservedObject
でインスタンスを使い回すケースを調べても親からインスタンスを渡す、と言うサンプルはあまり見当たらないのですが、これでやらないと先のObservableObject
で設定した変数を参照できません。
で、ここではPDFViewer(pdfInfo: pdfInfo)
で、実際のPDFの表示を行なっています。
PDFViewer()について
PDFの設定についてはUIViewControllerなどでの書き方はほとんど一緒ですが、
struct PDFViewer: UIViewRepresentable {
@ObservedObject var pdfInfo: PDFInfo
let url: URL = Bundle.main.url(forResource: "Oz was Wizard - Original Soundtrack", withExtension: "pdf")!
func makeUIView(context: UIViewRepresentableContext<PDFViewer>) -> PDFViewer.UIViewType {
<ここでPDFの設定>
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PDFViewer>) {
}
}
と言う形でUIViewRepresentable
を使って実装しています。
参照:
- https://developer.apple.com/documentation/swiftui/uiviewrepresentable
- https://qiita.com/k_awoki/items/448fd0bd6f51500d13b1
UIKitを使うにあたってはこれと同じような書き方をすれば良いようです。
PDFの設定周りはソースや他のリソースを参考にして貰えば。
このサンプルで出来なかったこと
PDFを拡大/縮小する機能を無効にしたかったんですが、これはPDFKitでは機能的には実装されていないので、まだ調べていますがやり方が分かる方教えてもらえたら嬉しいです。