Xcode
iOS
Swift

【決定版】UIPageViewControllerの使い方(Swift)

More than 1 year has passed since last update.


UIPageViewControllerとは

(※僕自身の個人的な解釈、予想です。)

UIPageViewControllerとは画面遷移に使われる一種のコントローラーです。NavigationControllerやTabBarControllerのようなものです。

実際のアプリケーションでは、SmartNews、SnapChat、TinderなどのUIや、様々なアプリケーションの初回起動時の使用方法説明画面などに使われています。

UIScrollViewでもにたような機能は実装できるのですが、別々なViewControllerをつなげることができるUIPageViewControllerの方がすっきりとしたコードが書けるようになるため、優れていると思います。

日本語の文献が少なく実装に苦労したので、ここにまとめたいと思います。一度覚えてしまえば、簡単に実装ができ、また便利な機能なので頑張っていきましょう!


完成図

aaa.gif


実装手順

1.繋げたいViewControllerを用意

2.UIPageViewControllerを作成

3.コードを記述


ViewControllerを準備


1.画像を参考に3つ適当なViewControllerを準備してください。それぞれ区別がつけば、レイアウトなどは適当で構いません。

スクリーンショット 2016-04-10 4.41.28 AM.png


2.それに対応したファイルも3つ作って、それぞれのViewControllerに指定してください。


3.また、StoryBoardIDも忘れずに設定するようにしましょう。

スクリーンショット 2016-04-10 4.46.22 AM.png

以上の3つのViewControllerをUIPageViewControllerを使い、スワイプで画面遷移できるようにしていきたいと思います。


UIPageViewControllerを準備


1.オブジェクトライブラリからドラック&ドロップでUIPageViewControllerを追加

スクリーンショット 2016-04-10 4.48.52 AM.png


2.画像を参考にUIPageViewControllerの設定を変更

スクリーンショット_2016-04-10_4_51_19_AM.png

以上がが、StoryBoardでの作業になります。

ここまでをまとめると、繋げたいViewControllerとPageViewControllerを用意し、StoryboardID、TransitionStyle、InitialViewControllerなどの設定をしただけです。

次からはソースコードでの作業になります。


UIPageViewControllerを編集しよう


1.まずUIPageViewControllerクラスを継承したファイルを作成

ファイル名は、「PageViewController」にしてください。

忘れずに、StoryboardのUIPageViewControllerとの関連付けもしましょう。


2.最初の画面を設定

ファイルを以下のように編集しましょう


PageViewController.swift

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ファイルを編集してください。


PageViewController.swift


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を繋げていきます。

クラス内の適当な箇所に以下のように追記してください。


PageViewController.swift

func getSecond() -> SecondViewController {

return storyboard!.instantiateViewControllerWithIdentifier("SecondViewController") as! SecondViewController
}

func getThird() -> ThirdViewController {
return storyboard!.instantiateViewControllerWithIdentifier("ThirdViewController") as! ThirdViewController
}


そして、先ほどのデリゲードメソッドを次のように編集しましょう。

(注)pageViewController(___After_)メソッドです


PageViewController.swift

    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_)メソッドに次のように記述してあげることで実装できます。


PageViewController.swift

    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
}
}


完成コード


PageViewController.swift

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
}
}
}