Help us understand the problem. What is going on with this article?

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

More than 3 years have 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
        }
    }
}
timee
日本の労働力の減少を若者の働き方改革で解決します。好きな時に好きなだけ働けるプラットフォームタイミーを作り、人々が好きなことをできる世界を実現します。
https://timee.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした