【Swift】UIPageViewControllerとContainerViewを利用してタップで画面遷移

今年の４月から新卒入社でSwiftを勉強し始めました。
Swift初心者のためお見苦しい点が多々あると思いますので、お気軽にご指摘のコメント等いただけたら幸いです。

#はじめに
UIPageViewControllerの勉強をした際、スワイプ以外で画面遷移が出来て感動したため記事にしようと思いました。

##作成したもの
親のViewControllerにあるボタンをタップをしたら親のViewControllerの中に置いたContainerViewが次のページに遷移する。
![TapViewControllerGIF.gif](https://qiita-image-store.s3.amazonaws.com/0/308698/13a450cc-e9e6-c58b-9a61-e478287ffdf4.gif)

###UIPageViewControllerとは
スワイプで用意したViewControllerに画面遷移ができる
画面遷移時にアニメーションを付けられる

###ContainerViewとは
ViewControllerの中にViewControllerを配置することができるもの。
xibじゃなくてViewControllerを置きたい！という時に利用する。
ContainerViewは複数設置することも可能

##作ってみた
<img width="562" alt="StoryBoard.png" src="https://qiita-image-store.s3.amazonaws.com/0/308698/3e16949f-7090-d067-b0a0-44640f827c07.png">

親となるViewController(ContainerView)、UIPageViewController、子となるViewControllerを用意

<img width="201" alt="Embed.png" src="https://qiita-image-store.s3.amazonaws.com/0/308698/56c9f37f-fe00-b5ce-357f-0a64f4ba0341.png">

ViewControllerにあるContainerViewから
「control+ドラッグ」でUIPageViewControllerに紐づけて「Embed」を選択すればOK

<img width="261" alt="StoryboardID.png" src="https://qiita-image-store.s3.amazonaws.com/0/308698/2f41b34f-4639-3f42-5b4b-d352cf97e571.png">
画面遷移時にStoryboardIDを利用するため、StoryboardIDを設定


```ViewController.swift
import UIKit

class ViewController: UIViewController {
    
    var pageViewController: UIPageViewController?
    
    // 画面の切り替えを見た目でわかりやすくための背景色設定用カラーパレット
    var pallet = [UIColor.red, UIColor.yellow, UIColor.blue, UIColor.green, UIColor.purple]

    // 表示するViewControllerを判断するための数字
    var cnt = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // PageViewControllerを取得
        pageViewController = children.first! as? UIPageViewController
        setViewController()
    }
    
    // 次へボタンが押されたら
    @IBAction func tapNextButton(_ sender: UIButton) {
        // 次の画面を表示するため、cntを1増やす
        cnt += 1
        setViewController()
    }
    
    func setViewController() {
        if cnt < pallet.count {
            let contentVC = storyboard?.instantiateViewController(withIdentifier: "ContentViewController") as! ContentViewController
          
            // 遷移先のViewControllerにpalletの色を送る
            contentVC.backColor = pallet[cnt]
            // PageViewControllerにViewControllerをセット
            self.pageViewController?.setViewControllers([contentVC], direction: .forward, animated: true,completion: nil)
        }
    }
}
```

##おまけ
###ドラッグでも画像遷移できるようにもしてみた

![DragViewControllerGIF.gif](https://qiita-image-store.s3.amazonaws.com/0/308698/1ee5dbe0-9ebc-1118-c033-f55616afaac6.gif)

pageViewControllerのdataSourceを自身に設定
これをしないとドラッグしても反応しない

```ViewController.swift
 // dataSourceの設定を追記
 pageViewController?.dataSource = self
```

UIPageViewControllerDataSourceを継承する

```ViewController.swift

extension ViewController: UIPageViewControllerDataSource {

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {

    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {

    }
}
```

継承するとメソッドを追加してね！という注意が出ます。
注意に従ってメソッドを追加すると上記のメソッドが追加されます。

このメソッドに関して

>  // In terms of navigation direction. For example, for 'UIPageViewControllerNavigationOrientationHorizontal', view controllers coming 'before' would be to the left of the argument view controller, those coming 'after' would be to the right.

→'UIPageViewControllerNavigationOrientationHorizo​​ntal'の場合、
 **'before'**にあるビューコントローラは引数ビューコントローラ(現在表示されているViewController)の左側にあり、 
 **'after'**は右側にあります。

説明に従って適したViewControllerを準備していきます。

```ViewController.swift
extension ViewController: UIPageViewControllerDataSource {
    // Beforeなので左側のViewController
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
      let contentVC = storyboard?.instantiateViewController(withIdentifier: "ContentViewController") as! ContentViewController
        if 0 < cnt {
            cnt -= 1
            contentVC.color = pallet[cnt]
        }
        return contentVC
    }
    // Afterなので右側のViewController
       func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        cnt += 1
        let contentVC = storyboard?.instantiateViewController(withIdentifier: "ContentViewController") as! ContentViewController
        if cnt < pallet.count {
            contentVC.color = pallet[cnt]
        }
        return contentVC
    }
}
```


##おわり
UIPageViewControllerが想像していたものと少し違う感じでしたが便利でした。
今回は１つのViewControllerで実装しましたが、もちろん複数のViewControllerでも実装可能です。