SwiftのUIPageViewControllerの基本的な使い方(ストーリーボードなし)

ページをめくる画面は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には「スクロール型」と「ページをめくる型」がある。デフォルトは後者だが、後者はアニメーションが独特であり、本を読むアプリでない限りは前者を採用したほうが無難になる。

ページをめくる画面はUIPageViewControllerで設計する…presentationCountと2つのpageViewControllerを用意する。presentationCountは上のコードにあるようにpagesの数を返すだけの関数。UIPageViewControllerというクラス、そしてページ画面のポイントは2つのpageViewControllerにある。UIPageViewControllerはページを戻るときと、ページを進めるときの動作を表す。