Swiftでスライドメニュー(SWRevealViewController)をStoryboardを使わず、アプリ途中から使用


Swiftでは基本的にStoryboardを使わずにコードだけで画面も遷移も作ってます。
ナビゲーションバー上のハンバーガーボタンを押すと、横にスライドするサイドメニューが欲しくてSwiftで使えるライブラリを探した結果、今回はSWRevealViewControllerというライブラリを使わせてもらいました。
シンプルですが、綺麗なUIです。

一部実装の際にハマったので、記事として導入の流れを残しておきたいと思います。

GitHub
[John-Lluch/SWRevealViewController](https://github.com/John-Lluch/SWRevealViewController)

Storyboardを使った場合の導入チュートリアル
[Creating a Sidebar Menu Using SWRevealViewController in Swift](http://www.appcoda.com/sidebar-menu-swift/)

(Facebookがこの形のメニューを最初に使ったのは知らなかった...)

## 1.実装したいこと
最初にログイン画面があるアプリケーションを想定しています。
ログインが完了した後のホーム画面からナビゲーションバーが設置され、そのナビゲーションバーにはスライドサイドメニューが実装されている、という構成です。

## 2.ライブラリの導入
冒頭に上げたチュートリアルに詳しいです。

私はCocoaPodsを用いています。
Objective-Cのライブラリなので、`pod install` が完了したあとに、`Bridging-Header.h` ファイルに下記を追記します。

```
#import "SWRevealViewController.h
```

同時に、Buid SettingのObjective-C Bridging Header 項目に下記を追記するのもお忘れなく。

```
$(SRCROOT)/$(PRODUCT)/Bridging-Header.h
```

## 3.Controllerの構成
####必要なパーツ
- LoginViewController...ログイン画面
- SWRealViewController...メニューとホーム画面を接続するコントローラー(ライブラリで作られるので作成の必要なし)
- SidebarTableViewController...メニュー用のテーブルビューコントローラー
- NavigationController...ナビゲーション用のコントローラー(作成の必要無し)
- HomeViewController...ホーム画面

#### Controllerの流れ
LoginViewControllerからSWRealViewControllerを経由して、下記の1と2が表示される。
1はメニューバーがタップされるまで2の後ろに隠れている。という構成です。

LoginViewController => SWRealViewController =>

1(rear) => SidebarTableViewController
2(front) => NavigationController => HomeViwController

## 4.サイドメニュー用のテーブルビュー
これもStoryboardを使わずに実装します。
ここだけでも説明すると1つのコンテンツになってしまうので、まるっとコードを載せてしまいます。
ポイントは下記かと。
- delegate, dataSource にselfを関連づけることを忘れない
- cellをregisterする


```SidebarTableViewController.swift
import UIKit

class SidebarTableViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
    
    var tableView: UITableView  =   UITableView()
    var items: [String] = ["menu1", "menu2", "menu3"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        //テーブルビュー初期化、関連付け
        tableView.frame = UIScreen.mainScreen().bounds 
        tableView.delegate = self
        tableView.dataSource = self
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
        self.view.addSubview(tableView)
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell!
        cell.textLabel?.text = self.items[indexPath.row]
        return cell
    }
    
    // メニューをタップした時のアクション
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        print("セル #\(indexPath.row)!")
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
};
```

## 5.ホーム画面用のController
これはラベルを1つ入れただけのホーム画面です。

`if self.revealViewController() != nil` のif文で、サイドメニューをターゲットにしてメニューボタンによりアクションが発生する機能を実装しています。

```
import UIKit

class HomeViewController: UIViewController {
    
    lazy private var label: UIView  = self.createLabel()
    var addBtn: UIBarButtonItem!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
 
       	 // 背景色
        self.view.backgroundColor = UIColor.whiteColor()
        
        // labelの設置 
		 self.view.addSubview(label)

        // ナビゲーションバーの設定
        self.navigationController!.navigationBarHidden = false
        self.title = "Home"
        
        // ナビゲーションバー内にMenuボタンの設置
        let uiBarButtonItem : UIBarButtonItem = UIBarButtonItem(title: "Menu", style: UIBarButtonItemStyle.Plain, target: self, action: "tapBarButtonItem:")
        let uiBarButtonItems: NSArray = [uiBarButtonItem]
        self.navigationItem.setLeftBarButtonItems((uiBarButtonItems as! [UIBarButtonItem]), animated: true)
                
        // targetとactionを設定
        if self.revealViewController() != nil {
            uiBarButtonItem.target = self.revealViewController()
            uiBarButtonItem.action = "revealToggle:"
            self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
        }
    }
    
    
    // レイアウト用のoverride
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.layoutLabel()
    }
    
    
    // Labelの作成
    private func createLabel() -> UIView {
        let label = UILabel(frame: CGRectZero)
        label.text = "HOME"
        return label
    }
    
    // Lavelのレイアウト
    private func layoutLabel() {
        label.frame = CGRectMake(0, 100, 300, 50)
        label.center.x = self.view.center.x
    }
   
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}
```


## 6.ホーム画面への遷移アクション
3で記載した通りのControllerの流れを、LoginViewControllerに実装します。
なんだかんだ、この部分が一番のキモだと思います。
ここの試行錯誤でハマりました...

```LoginViewController.swift
func buttonAction(sender: UIButton!) {

	// HomeViewControllerとNavigationControllerをつなげる
    let homeViewController = HomeViewController()
    let navigationController = UINavigationController(rootViewController: homeViewController)
    
    // NavigationControllerをfront, SidebarTableViewControllerをrearにし、
    // SWRevealViewControllerに接続
    let frontViewController  = navigationController
    let rearViewController  = ()
    let swRevealVC = SWRevealViewController(rearViewController: rearViewController, frontViewController: frontViewController);
    swRevealVC.toggleAnimationType = SWRevealToggleAnimationType.EaseOut;
    swRevealVC.toggleAnimationDuration = 0.30;

	// SWRevealViewControllerに遷移する
    presentViewController(swRevealVC, animated: true, completion: nil)
    
}
```

## 7.完成!
ちゃんと動きました！

![sidebar.gif](https://qiita-image-store.s3.amazonaws.com/0/87650/22156106-f5c7-7575-d567-e2a519bac5f4.gif "sidebar.gif")


ここからもっとおしゃれなものにいじっていきたいと思います。