Swiftでは基本的にStoryboardを使わずにコードだけで画面も遷移も作ってます。
ナビゲーションバー上のハンバーガーボタンを押すと、横にスライドするサイドメニューが欲しくてSwiftで使えるライブラリを探した結果、今回はSWRevealViewControllerというライブラリを使わせてもらいました。
シンプルですが、綺麗なUIです。
一部実装の際にハマったので、記事として導入の流れを残しておきたいと思います。
GitHub
John-Lluch/SWRevealViewController
Storyboardを使った場合の導入チュートリアル
Creating a Sidebar Menu Using SWRevealViewController in 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する
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に実装します。
なんだかんだ、この部分が一番のキモだと思います。
ここの試行錯誤でハマりました...
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.完成!
ちゃんと動きました!
ここからもっとおしゃれなものにいじっていきたいと思います。