【Swift】SideMenuでサイドメニューを作る

どうも、ねこきち(@nekokichi1_yos2)です。

 

今回は多くのアプリで使われている、サイドバー/サイドメニュー、を下記のライブラリで実装します。

github.com

 

(参考)

qiita.com

kimagureneet.hatenablog.com

解説

 

準備 

 

まず、

  • 3つのファイルを作る(メニュー表示/設定用、メニュー項目用(TableViewControllerじゃないとダメ))
  • ストーリーボードで2つのビューコントローラを設置(ViewController、NavigationController)
  • 各ビューコントローラのクラスとモジュールを設定

を行います。

 

今回の実装はストーリーボードを活用してます。

 

実は、SideMenuを解説してる記事のほとんどはコードでの実装なんですが、記事通りに実装しても最終的にはエラーなどが原因で無理でした。

 

なので、SideMenuの公式マニュアルと同じく、ストーリーボードでの実装にしました。

 

実装 - ViewController

 

先ほど追加したTableViewControllerをインスタンス化。

//サイドメニュー用のtableViewを生成
let menuViewController = TableViewController()

 

SideMenuのナビゲーションコントローラを生成。

rootViewControllerには、TableViewController()を持ったmenuViewControllerを指定。

//サイドメニューのナビゲーションコントローラを生成
let menuNavigationController = SideMenuNavigationController(rootViewController: menuViewController)

 

ナビゲーションコントローラをSideMenuのメニューとして追加。

スワイプ動作の追加も、UISwipeGestureRecognizer、を用意しなくても、SideMenu側で実装可能。

//左,右のメニューとして追加
SideMenuManager.default.leftMenuNavigationController = menuNavigationController
SideMenuManager.default.rightMenuNavigationController = menuNavigationController
//左、右スワイプジェスチャーを追加
SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: self.view, forMenu: .left)
SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: self.view, forMenu: .right)

 

SideMenu側でメニューの設定を行う。

他にも色々な設定値があるが、基本的にはこれだけで十分。

    //サイドメニューの設定
    private func makeSettings() -> SideMenuSettings {
        var settings = SideMenuSettings()
        //動作を指定
        settings.presentationStyle = .menuSlideIn
        //メニューの陰影度
        settings.presentationStyle.onTopShadowOpacity = 1.0
        //ステータスバーの透明度
        settings.statusBarEndAlpha = 0
        return settings
    }
    

 

「onTopShadowOpacity」

影を付ければ、立体感が出る。

f:id:nekokichi_yos2:20200429133216p:plain

 

「statusBarEndAlpha」

初期値は1で、ステータスバーが黒くなる。

f:id:nekokichi_yos2:20200429133110p:plain

 

実装 - TableViewController

 

特にSideMenu関連のコードは必要なし。

 

ただ、カスタムセルを登録しないと、エラーが出てしまう。

'unable to dequeue a cell with identifier cell - must register a nib or a class 
for the identifier or connect a prototype cell in a storyboard'

 

とりあえず、登録しておくだけでOK。

tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier:  "customcell")

 

ストーリーボード

 

f:id:nekokichi_yos2:20200429124952p:plain

 

f:id:nekokichi_yos2:20200429124220p:plain

 

「ViewController」

f:id:nekokichi_yos2:20200429124326p:plain

「NavigationController」

f:id:nekokichi_yos2:20200429124330p:plain

「RootViewController」

f:id:nekokichi_yos2:20200429124333p:plain

 

ソースコード

 

import UIKit
import SideMenu

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        //サイドメニュー用のtableViewを生成
        let menuViewController = TableViewController()
        //サイドメニューのナビゲーションコントローラを生成
        let menuNavigationController = SideMenuNavigationController(rootViewController: menuViewController)
        //設定を追加
        menuNavigationController.settings = makeSettings()
        //左,右のメニューとして追加
        SideMenuManager.default.leftMenuNavigationController = menuNavigationController
        SideMenuManager.default.rightMenuNavigationController = menuNavigationController
        //左、右スワイプジェスチャーを追加
        SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: self.view, forMenu: .left)
        SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: self.view, forMenu: .right)
    }
    
    //サイドメニューの設定
    private func makeSettings() -> SideMenuSettings {
        var settings = SideMenuSettings()
        //動作を指定
        settings.presentationStyle = .menuSlideIn
        //メニューの陰影度
        settings.presentationStyle.onTopShadowOpacity = 1.0
        //ステータスバーの透明度
        settings.statusBarEndAlpha = 0
        return settings
    }
    
}     let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel!.text = num[indexPath.row]
        return cell
    }
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        //メインスレッドでtableViewを更新
        DispatchQueue.main.async {
            if indexPath.row == self.num.count - 5 {
                self.num.append(contentsOf: self.num)
                tableView.reloadData()
            }
        }
    }
    
}

 

import UIKit

class TableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.separatorStyle = .none
        tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier:  "customcell")
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "メニュー"
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "customcell", for: indexPath)
        cell.textLabel?.text = "\(indexPath.row)"
        cell.textLabel?.textAlignment = .center
        return cell
    }

}

 

結果

 

f:id:nekokichi_yos2:20200429124532p:plainf:id:nekokichi_yos2:20200429124536p:plain