LoginSignup
25
15

More than 5 years have passed since last update.

pageViewController(_: viewControllerBefore:) および pageViewController(_: viewControllerAfter:) が呼び出されるタイミングについて(UIPageViewController)

Last updated at Posted at 2017-06-06

前提

  • Swift 3
  • 表示するViewControllerは常時1枚だけ

経緯

  • publicなプロパティにセットされた数字を表示するだけのViewControllerがある
  • UIPageViewControllerを使い、端の制限がないページングを行いたかった
    • スワイプすることで上記ViewControllerの数字をカウントアップ、カウントダウンさせたかった

tl;dr

  • PageViewControllreは表示中のViewControllerの前後になるべくViewControllerを生成して待機させている
  • 初期化してから初めてのページング開始時にpageViewController(_: viewControllerBefore:)およびpageViewController(_: viewControllerAfter:)が一度ずつ呼ばれる
  • ページング完了時に、ページング方向応じてpageViewController(_: viewControllerBefore:)およびpageViewController(_: viewControllerAfter:)が一度呼ばれる
  • 引数のviewControllerを元に相対で適切な値を決定してあげましょう

期待したとおりに動かないコード

class ViewController: UIViewController {
    public var number: Int = 0
    @IBOutlet weak var simpleLabel: UILabel!

    override func viewWillAppear(_ animated: Bool) {
        simpleLabel.text = number.description
    }
}
class PageViewController: UIPageViewController, UIPageViewControllerDataSource {
    var number: Int = 0
    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self

        // 初期表示するViewControllerをセットする
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        vc.number = self.number
        self.setViewControllers([vc], direction: .forward, animated: true)
    }
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        // 後方のViewControllerを生成するため、カウントダウンしたい
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        self.number -=1
        vc.number = self.number
        return vc
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        // 前方のViewControllerを生成するため、カウントアップしたい
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        self.number +=1
        vc.number = self.number
        return vc
    }

}

期待したとおりに動くコード

class ViewController: UIViewController {
    public var number: Int = 0
    @IBOutlet weak var simpleLabel: UILabel!

    override func viewWillAppear(_ animated: Bool) {
        simpleLabel.text = number.description
    }
}
class PageViewController: UIPageViewController, UIPageViewControllerDataSource {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self

        // 初期表示するViewControllerをセットする
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        vc.number = 0
        self.setViewControllers([vc], direction: .forward, animated: true)
    }
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        // 後方のViewControllerを生成するため、カウントダウンしたい
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        vc.number = (viewController as! ViewController).number - 1
        return vc
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        // 前方のViewControllerを生成するため、カウントアップしたい
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        vc.number = (viewController as! ViewController).number + 1
        return vc
    }

}

該当メソッドが呼び出されるタイミングについて整理

PageViewController初期化からページング完了までを図解

pagevc-1.jpg
これはPageViewController.viewDidLoad()が完了した直後のイメージ図です。
薄緑色は上記のViewController、外側の枠はPageViewControllerです。

pagevc-1 (1).jpg
After方向のスワイプイベントが発生しました。

pagevc-1 (2).jpg
ページングを開始しますが、表示するViewControllerが存在しないため、pageViewController(_: viewControllerAfter:)を呼び出し、先のViewControllerを生成します。

pagevc-1 (3).jpg
また、Before方向のViewControllerも存在していないためにpageViewController(_: viewControllerBefore:)も呼び出し、後方のViewControllerも生成します。

pagevc-1 (4).jpg
ページング中……

pagevc-1 (5).jpg
ページングが完了しました。次のページング処理に備え、pageViewController(_: viewControllerAfter:)を呼び出し、先のViewControllerを生成します。

問題のコードでは何が起きていたか

pagevc-1 (6).jpg
問題のコードをより反映した図になります。丸い要素はPageViewController.numberを表したものです。

pagevc-1 (7).jpg
After方向のスワイプイベントが発生して先のViewControllerが生成されました。
pageViewController(_: viewControllerAfter:)によってPageViewController.numberがカウントアップされます。

pagevc-1 (8).jpg
また、後方のViewControllerも生成されました。
pageViewController(_: viewControllerBefore:)によってPageViewController.numberがカウントダウンされます。

pagevc-1 (9).jpg
ページング中……

pagevc-1 (10).jpg
ページングが完了しました。次のページング処理に備え、先のViewControllerを生成します。
pageViewController(_: viewControllerAfter:)によってPageViewController.numberがカウントアップされます。

まとめ

  • pageViewController(_: viewControllerBefore:)およびpageViewController(_: viewControllerAfter:)では、生成されようとしているViewControllerの前後のViewControllerが取得できる
  • なので、前後のViewControllerに対してどういう値が適切なのかを考えるようにする
25
15
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
15