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+
