#UIPageViewControllerとは
(※僕自身の個人的な解釈、予想です。)
UIPageViewControllerとは画面遷移に使われる一種のコントローラーです。NavigationControllerやTabBarControllerのようなものです。
実際のアプリケーションでは、SmartNews、SnapChat、TinderなどのUIや、様々なアプリケーションの初回起動時の使用方法説明画面などに使われています。
UIScrollViewでもにたような機能は実装できるのですが、別々なViewControllerをつなげることができるUIPageViewControllerの方がすっきりとしたコードが書けるようになるため、優れていると思います。
日本語の文献が少なく実装に苦労したので、ここにまとめたいと思います。一度覚えてしまえば、簡単に実装ができ、また便利な機能なので頑張っていきましょう!
#実装手順
1.繋げたいViewControllerを用意
2.UIPageViewControllerを作成
3.コードを記述
##ViewControllerを準備
####1.画像を参考に3つ適当なViewControllerを準備してください。それぞれ区別がつけば、レイアウトなどは適当で構いません。
####2.それに対応したファイルも3つ作って、それぞれのViewControllerに指定してください。
####3.また、StoryBoardIDも忘れずに設定するようにしましょう。
以上の3つのViewControllerをUIPageViewControllerを使い、スワイプで画面遷移できるようにしていきたいと思います。
##UIPageViewControllerを準備
####1.オブジェクトライブラリからドラック&ドロップでUIPageViewControllerを追加
####2.画像を参考にUIPageViewControllerの設定を変更
以上がが、StoryBoardでの作業になります。
ここまでをまとめると、繋げたいViewControllerとPageViewControllerを用意し、StoryboardID、TransitionStyle、InitialViewControllerなどの設定をしただけです。
次からはソースコードでの作業になります。
##UIPageViewControllerを編集しよう
####1.まずUIPageViewControllerクラスを継承したファイルを作成
ファイル名は、「PageViewController」にしてください。
忘れずに、StoryboardのUIPageViewControllerとの関連付けもしましょう。
####2.最初の画面を設定
ファイルを以下のように編集しましょう
import UIKit
class PageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setViewControllers([getFirst()], direction: .Forward, animated: true, completion: nil)
}
func getFirst() -> FirstViewController {
return storyboard!.instantiateViewControllerWithIdentifier("FirstViewController") as! FirstViewController
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
ここではStoryboardからFirstViewControllerを読み込み、それをsetViewControllers()メソッドを使い、初期画面に設定しています。また、setViewControllers()メソッドの第一引数は配列になっていますが、基本的に1つのViewControllerを入れるだけで構いません。iBooksのようなアプリを作る場合に複数のViewControllerを入れます。(この点については今回は詳しく触れませんが、気になる方は調べてみてください。)
このタイミングで一度ビルドして、正常に起動するか確認してください。
####3.dataSource
次の残りの2つのViewControllerをつなげていきたいと思います。
次のようにPageViewControllerファイルを編集してください。
import UIKit
class PageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setViewControllers([getFirst()], direction: .Forward, animated: true, completion: nil)
self.dataSource = self //追加
}
省略
}
//以下追加
extension PageViewController : UIPageViewControllerDataSource {
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
return nil
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
return nil
}
}
複数のViewControllerはdataSourceプロトコルを使い実装していきます。
####4.最後に残りの2つのViewControllerを繋げていきます。
クラス内の適当な箇所に以下のように追記してください。
func getSecond() -> SecondViewController {
return storyboard!.instantiateViewControllerWithIdentifier("SecondViewController") as! SecondViewController
}
func getThird() -> ThirdViewController {
return storyboard!.instantiateViewControllerWithIdentifier("ThirdViewController") as! ThirdViewController
}
そして、先ほどのデリゲードメソッドを次のように編集しましょう。
(注)pageViewController(__After)メソッドです
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
if viewController.isKindOfClass(FirstViewController) {
// 1 -> 2
return getSecond()
} else if viewController.isKindOfClass(SecondViewController) {
// 2 -> 3
return getThird()
} else {
// 3 -> end of the road
return nil
}
}
もし現在の画面が
・FirstVCだった場合、SecondVCを
・SecondVCだった場合、ThirdVCを
・FirstVCだった場合、次(After)のページはないのでnilを
返しています。
逆もしかりです。
ページを戻す場合は、pageViewController(__before)メソッドに次のように記述してあげることで実装できます。
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
if viewController.isKindOfClass(ThirdViewController) {
// 3 -> 2
return getSecond()
} else if viewController.isKindOfClass(SecondViewController) {
// 2 -> 1
return getFirst()
} else {
// 1 -> end of the road
return nil
}
}
#完成コード
import UIKit
class PageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setViewControllers([getFirst()], direction: .Forward, animated: true, completion: nil)
self.dataSource = self
}
func getFirst() -> FirstViewController {
return storyboard!.instantiateViewControllerWithIdentifier("FirstViewController") as! FirstViewController
}
func getSecond() -> SecondViewController {
return storyboard!.instantiateViewControllerWithIdentifier("SecondViewController") as! SecondViewController
}
func getThird() -> ThirdViewController {
return storyboard!.instantiateViewControllerWithIdentifier("ThirdViewController") as! ThirdViewController
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension PageViewController : UIPageViewControllerDataSource {
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
if viewController.isKindOfClass(ThirdViewController) {
// 3 -> 2
return getSecond()
} else if viewController.isKindOfClass(SecondViewController) {
// 2 -> 1
return getFirst()
} else {
// 1 -> end of the road
return nil
}
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
if viewController.isKindOfClass(FirstViewController) {
// 1 -> 2
return getSecond()
} else if viewController.isKindOfClass(SecondViewController) {
// 2 -> 3
return getThird()
} else {
// 3 -> end of the road
return nil
}
}
}