UIPageViewControllerのエンドレス化などなど
Dec 13, 2016 · iosswift3
UIPageViewController
をエンドレスでページ切り替えする方法とかその他小ネタ
エンドレスの挙動は、最後のページから次へ進むと最初のページへ、最初のページからさらに戻ると最後のページへ移動する感じ。 詳細はサンプルを参照のこと
作成の流れ
まず、画面の構造は以下の通り。ページ部分はChildViewController
にしているが、
UIPageViewController
を全画面にしている場合も同じ
ViewController
└─ Container View
└─ UIPageViewController
└─ (各ページ)
ページの生成
今回はページ数が固定(5ページ)を想定しているので、viewDidLoad
でページのリストをあらかじめ生成しておく
// var pages = [PageViewController]()
pages = Array(1...5).flatMap {
guard let vc = storyboard?.instantiateViewController(withIdentifier: "Page") as? PageViewController else {
return nil
}
// 各ページの設定
return vc
}
リストを生成したら、初期表示するページを設定
setViewControllers([pages[0]], direction: .forward, animated: false)
ページングの処理
UIPageViewControllerDataSource
の
viewControllerBefore
とviewControllerAfter
を実装する
viewControllerBefore
だとこんな感じで前のページを返す
guard let vc = viewController as? PageViewController,
var index = pages.index(of: vc) else { return nil }
index -= 1
index = (index < pages.startIndex) ? pages.endIndex - 1 : index
return pages[index]
ポイントは基準となるページ(引数で渡されるviewController
)のインデックスをページのリストから検索して見つけること
(コードではindex = pages.index(of: vc)
)
例えば、現在表示中のページのインデックスをプロパティに持っておく方法ではうまくいかない。 なぜならこのデリゲートは現在表示中のページ以外からも呼び出されるので
小ネタ
UIPageViewControllerのStoryboardへの追加
追加する時は、右下のUIパーツが並んでいるところからPageViewController
を選んで追加すること
通常のViewController
で追加してしまうと後から変更しても、UIPageViewController
の設定項目が出てこない。。。
ページを表示した時に各UIの位置が一瞬ずれて表示されてしまう場合
AutoLayout
の基準がLayoutGuide
になっているとダメな場合があるのでView
を基準に変えてみる
(例えば上部はTopLayoutGuide
ではなく、View
からにする。Constrain to margins
はチェックを外す)
Container Viewの中のViewControllerを取得する
Container View
とChildViewController
を繋ぐsegue
のdestination
から取得できる
private weak var pager: PagerViewController!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.destination {
case let vc as PagerViewController:
pager = vc
default: break
}
}
ちなみに、今回はContainer View
のPagerViewController
は1つなので上記の判定だが、
同じクラスのものが複数ある場合は、segue
のidentifier
で判定すれば良い
(もちろん、Storyboard
上で別々のIDを設定しておく)
開発環境
- Xcode 8.1
- iOS 10.1.1
- iPhone 7+