UIPageViewControllerを使ってみる

# UIPageViewControllerを使ってみた
## 目的
既存のアプリの画像プレビュー画面をつくるため

状況として

- NavigationControllerとTabControllerのついたViewからpushされる
- AutoLayoutを使用している

この２つの時。ちょっとつまづくところや自分で工夫してみたところがあるので

## 導入方法

1. StoryboardにPageViewControllerを設置してsegueを貼る
2. Storyboardに表示したいページになるViewControllerを設置する
3. 今回はAutoLayoutがナビゲーションバーの高さとタブバーの高さに依存してほしいから子となるViewControllerにPageViewControllerから適当に使わないsegueを貼った（もっといい方法あれば教えて下さい。。。）
4. 子のViewControllerは画像を表示するだけなのでOutletだけ接続しWillAppearの段階で画像を反映させるようにするだけでオーケー
5. PageViewControllerにはDataSourceとDelegateを継承して設定（デフォルトのサンプルだとDataSourceとDelegateの継承クラスは２つにわけてるけど今回はいっぺんに）

コードはこんな感じです。Utility以下は必ず作らないといけないわけではなくて何らかの形でその処理の内容が実現できてればいいです。

```swift
import UIKit

class ImagePreViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var pageData: NSMutableArray!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
        
        let startViewController: PreViewController = self.viewControllerAtIndex(0, storyboard: self.storyboard!)!
        let viewControllers = [startViewController]
        self.setViewControllers(viewControllers, direction: .Forward, animated: false, completion: {done in })
        
        self.dataSource = self
        self.view.gestureRecognizers = self.gestureRecognizers
    }
    
    // pageViewController関連----------------------------------------------------
    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        var index = self.indexOfViewController(viewController as! PreViewController)
        if index == 0 || index == NSNotFound {
            return nil
        }
        index--
        return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!)
    }
    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        var index = self.indexOfViewController(viewController as! PreViewController)
        if index == self.pageData.count - 1 || index == NSNotFound {
            return nil
        }
        index++
        return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!)
    }
    // 向きはPortrait限定なので常に表示されるページは一個
    func pageViewController(pageViewController: UIPageViewController, spineLocationForInterfaceOrientation orientation: UIInterfaceOrientation) -> UIPageViewControllerSpineLocation {
        let currentViewController = self.viewControllers![0]
        let viewControllers = [currentViewController]
        self.setViewControllers(viewControllers, direction: .Forward, animated: true, completion: {done in })
        self.doubleSided = false
        return .Min
    }
    
    // Utility------------------------------------------------------------------
    func indexOfViewController(viewController: PreViewController) -> Int {
        if let dataObject: AnyObject = viewController.imageData {
            return self.pageData.indexOfObject(dataObject)
        } else {
            return NSNotFound
        }
    }
    func viewControllerAtIndex(index: Int, storyboard: UIStoryboard) -> PreViewController? {
        if self.pageData.count == 0 || index >= self.pageData.count {
            return nil
        }
        let preViewController = storyboard.instantiateViewControllerWithIdentifier("PreViewController") as! PreViewController
        preViewController.imageData = self.pageData[index] as! NSData
        return preViewController
    }
}
```

pageViewControllerのviewControllerBeforeうんにゃらとviewControllerAfterうんにゃらが前後のViewを決めるdelegateメソッドになっています。内容はわりと[ここ](http://qiita.com/stenpel/items/c4d6f4e336a46734b084)を参考にしましたがようは今表示されてるViewが用意されてるViewの何枚目かを判断して決めているだけです。実際にはpageDataに画像のNSDataをぶっこむ処理をsegueのところでやっています。

## NavigationController+TabBarController+PageViewController
AutoLayoutのための工夫は先程言いました。しかしなにもしないままだと実はタップするまでNavigationBarの下にViewが表示されてしまいその後潜るという挙動が発生します。
このことに関しては[ここ](http://kohkimakimoto.hatenablog.com/entry/2014/12/03/145842)の追記を参考にAdjust Scroll View Insetsのチェックを外すことで直せました。