ページをめくる画面はUIPageViewControllerで設計する。この記事ではストーリーボードを使わないやり方を解説する。
基本的なコード
YourViewControllerというUIPageViewControllerを設計するとき、基本的なコードは次のようになる。
class YourViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var pages: [UIViewController] = []
override init(transitionStyle style: UIPageViewControllerTransitionStyle, navigationOrientation: UIPageViewControllerNavigationOrientation, options: [String : Any]? = nil) {
let t = UIPageViewControllerTransitionStyle.scroll
let n = UIPageViewControllerNavigationOrientation.horizontal
super.init(transitionStyle: t, navigationOrientation: n, options: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
let v = self.pages[0]
self.setViewControllers([v], direction: .forward, animated: true, completion: nil)
}
func presentationCount(for pageViewController: UIPageViewController) -> Int {
return pages.count
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let i = pages.index(of: viewController) else {
return nil
}
let p = i - 1
if p < 0 {
return nil
}
if pages.count <= p {
return nil
}
return pages[p]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let i = pages.index(of: viewController) else {
return nil
}
let n = i + 1
if n == pages.count {
return nil
}
if pages.count <= n {
return nil
}
return pages[n]
}
}
クラスの継承
UIPageViewControllerを使うときは
- UIPageViewController
- UIPageViewControllerDataSource
- UIPageViewControllerDelegate
の3つを継承する。
pagesを用意する
フィールド(クラスの変数)にページのデータを用意する。今回はpagesとした。pagesはUIViewControllerの配列である。
presentationCountと2つのpageViewControllerを用意する
presentationCountは上のコードにあるようにpagesの数を返すだけの関数。
UIPageViewControllerというクラス、そしてページ画面のポイントは2つのpageViewControllerにある。UIPageViewControllerはページを戻るときと、ページを進めるときの動作を表す。
- ページを戻す(viewControllerBefore)
- ページを進める(viewControllerAfter)
どちらも最初に
let i = pages.index(of: viewController)
で現在のページ番号を取得する。ページを戻すときはこの値に1引いた数、ページを進めるときはこの値に1足した数が「遷移後のページ番号」になる。
このページ番号は、0未満であっても、総ページ数を超えてもいけない。範囲を逸脱したときはnilを返す。
viewDidLoadではsetViewControllersを用意する
最初の画面さえ用意すれば「ページを戻す関数」と「ページを進める関数」に任せておけばいい。後は「最初のページを用意するもの」が必要だ。それがsetViewControllersになる。
setViewControllersには最初のページを入れる。
let v = self.pages[0]
self.setViewControllers([v], direction: .forward, animated: true, completion: nil)
不思議なことに最初のページ(UIViewController)は配列の形にしてsetViewControllersに入れる。
ページめくりのアニメーションはinitで決める
initで親のinitを呼び出す。その引数(transitionStyleとnavigationOrientation)でページめくりの形が決まる。
super.init(transitionStyle: t, navigationOrientation: n, options: nil)
transitionStyleには「スクロール型」と「ページをめくる型」がある。デフォルトは後者だが、後者はアニメーションが独特であり、本を読むアプリでない限りは前者を採用したほうが無難になる。