スワイプでページ切り替えを簡潔に実現する[Swift]



## はじめに
チュートリアルでよくあるスワイプでページ切り替えについてです。
もともと、ページングのためにpageViewControllerが用意されていますが、使おうとすると、非常に煩雑なコードを多く書かなければなりません。(メインのコードが埋もれる)

この記事は、メインのコードを、簡潔化させるのに役立ちます。
実装的に魔法のような部分が多いですが（すみません）、メインのコードをかなり簡潔化できます！



## 環境
iOS
Swift 2.0 (Swift1.2のコードを、Xcode7.0で動作可能なように変更しただけです)
Xcode 7.0




## サンプル
サンプル（ライブラリ？含む）はGitubで提供しています
[ha1fha1f/PagingViewController](https://github.com/ha1fha1f/PagingViewController)

gitに慣れている方はお好きなところにclone、
慣れてない方はターミナルを起動して以下のコマンドを実行してください。DesktopにPagingViewControllerフォルダができるかと思います。

```bash:git
cd ~/Desktop
git clone https://github.com/ha1fha1f/PagingViewController.git
```

そのままサンプルのプロジェクトになっているので、実行可能です。
![TutorialViewController_swift.png](https://qiita-image-store.s3.amazonaws.com/0/77778/1a9e4697-bafd-c439-4f00-f750e78ed114.png "TutorialViewController_swift.png")

PagingSample内がサンプル、PagingLibないがライブラリです。

このサンプルでは、チュートリアルのように5枚の写真が出てきて、最後のページだけStartボタンがある。そのStartを押すとViewControllerへと画面遷移する、という流れになっています。


## 最小限の利用方法
サンプルはほぼ最小構成になっています。

1. PagingViewController/PagingViewControllerLibにある3つの.swiftファイルをプロジェクトに追加
	- PagingViewController.swift
	- PagingDataController.swift
	- PagingCellViewController.swift
	<br /><br />
	
	
1. PagingCellViewControllerを継承したクラスをつくる
	これが各ページになります。
	最低限、
	
	```swift
	override func setDataObject(dataObject: AnyObject?) {}
	```
	
	をoverrideして、受け取ったdataObjectを適切にキャストしてフィールドとして保存してください
	その他は通常通りで、特殊な処理を書く必要はありません。
	
	サンプルを以下に示します。
	
	```swift
	class ImagePageCellViewController: PagingCellViewController{
		var imagePath: String!
		override func setDataObject(dataObject: AnyObject?){
        	if let tmpDataObject = dataObject {
        		self.imagePath = tmpDataObject as! String
        	}else{
				self.imagePath = "default.jpg"
        	}
    	}
    }
	```
	
	<br />
	
1. PagingDataControllerを継承したクラスをつくる
	これが全てのページを管理するクラスのサポートをします。
	最低限、
	
	```swift
	override func instanciateViewControllerAtIndex(index: Int) -> PagingCellViewController? {}
	```
	
	をoverrideして、indexに対応した、PagingCellViewControllerを継承したクラスのインスタンスを生成してreturnしてください。
	indexは何ページ目かを示します(0〜)
	
	サンプルを以下に示します
	
	```swift
	class TutorialPageDataController: PagingDataController {
		override func instanciateViewControllerAtIndex(index: Int) -> PagingCellViewController? {
    		let dataViewController: PagingCellViewController
        
        	// 最後のページだけ変えるサンプル
        	if index == (self.pageData.count-1) {
            	dataViewController = ImagePageCellLastViewController()
        	}else{
            	dataViewController = ImagePageCellViewController()
        	}
        
        	return dataViewController
    	}
    }
	```
	
	<br />
	
1. PagingViewControllerを継承したクラスをつくる
	これが全てのページをsubViewとしてもつViewControllerクラスになります。以下、親Controllerと呼びます。これもUIViewControllerを継承しています。
	最低限、PagingDataControllerを継承したクラスのインスタンスを作成して、setupWithDataControllerを実行する必要があります。
	
	サンプルを以下に示します
	
	```swift
	class TutorialViewController: PagingViewController {
		override func viewDidLoad() {
        	super.viewDidLoad()

        	let data = ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg", "pic5.jpg"] 
			self.setupWithDataController(TutorialPageDataController(data: data) 
		}
    }
	```
	
	<br />
	
1. これで最低限のページング処理を実現できます！


## 詳細
### PagingCellViewController（を継承したクラス）

```swift
self.sendMessageToRoot("test")
```
管理しているViewControllerに対してメッセージ(String)を送れます（正確には、親ControllerクラスのreceiveMessage()メソッドを呼び出しています）
self.delegateに親Controllerを入れてあるので、これを使うこともできます
self.indexを見ると自分が何ページ目なのか取得できます

PagingDataControllerでindexに応じて異なるクラスを作成することができるので、継承したクラスはいくつあっても問題ありません。

### PagingViewController（を継承したクラス）
これが親のcontrollerなので、この背景が、ページをスワイプしきったときの背景になります。逆に、どのページが表示されている時にも不動のもの(pageControlなど)を表示させることもできます。

ページングに関する設定項目は、

```swift
// ページの切り替わりのアニメーション
self.trasitionStyle = UIPageViewControllerTransitionStyle.Scroll

// ページ切り替わりの方向(縦横)
self.navigationOrientation = UIPageViewControllerNavigationOrientation.Horizontal

// PageControl(点が動く奴)が不要なときは
self.pageControl.removeFromSuperview()
```

self.pageControlの位置やサイズは、普通にいじれます

利用できるメソッドとしては、

```swift
// 特定のページヘジャンプする
moveTargetPage(index: Int)

// 今何ページ目を見ているか
getCurrentPageIndex() -> Int!

// 今見ているViewControllerのインスタンスを取得
getCurrentViewController() -> PagingCellViewController
```

オーバーライドできるメソッドとしては、

```swift
// 管理下のpageCellからのメッセージを受け取る
override func receiveMessage(message: String) {}
    
// ページ遷移後に呼ばれる。fromとtoはindexが渡される
override func afterPaging(from: Int, to: Int) {}

// ページ遷移前に呼ばれる。fromとtoはindexが渡される
override func beforePaging(from: Int, to: Int) {}
```
があります。

※いまPageControl用にafterPagingを用いているので、afterPagingのみsuper.afterPaging(from, to: to)を呼び出すようにお願いします


## おわりに
PageControlをライブラリに組み込む必要はなかったかもしれません、笑
Cocoapodsでインストールできるようにする、みたいなことはできるんでしょうか