【swift】UITableViewでUIMenuControllerをカスタマイズして使う方法

はじめに

今回やりたかったのはLINEみたいなかんじでセルを長押しすると削除とか編集とかのメニューをだしたかったことです。

で、デフォルトで「copy」とか「paste」とかの項目があるのですが、これらを削除してカスタマイズしたメニューだけ表示するというのがやりたかったことになります

f:id:yoppy0066:20150723012858p:plain
こんなかんじのメニューです

実装方法

テーブルに表示しているデータとかは適当です

ViewController.swift

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    var tableView: UITableView!
    var tableData: [String]!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // メニュー更新
        var menuItem: UIMenuItem = UIMenuItem(title: "編集", action: "edit:")
        var menuItem2: UIMenuItem = UIMenuItem(title: "削除", action: "remove:")
        var menuItem3: UIMenuItem = UIMenuItem(title: "登録", action: "regist:")
        UIMenuController.sharedMenuController().menuItems = [menuItem, menuItem2, menuItem3]
        UIMenuController.sharedMenuController().update()
        
        // テーブル表示
        tableData = ["りんご", "ばなな", "メロン"]
        
        let displayWidth = self.view.frame.width
        let displayHeight = self.view.frame.height
        
        let tableView = UITableView(frame: CGRect(x:0, y:0, width:displayWidth, height:displayHeight))
        tableView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier: "Cell")
        tableView.delegate = self
        tableView.dataSource = self
        
        self.view.addSubview(tableView)
    }
    
    // テーブルセルデータをセットします
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomTableViewCell
        cell.textLabel?.text = tableData[indexPath.row]
        return cell
    }
    
    // テーブルの行数を返します
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tableData.count
    }
    
    // テーブルセルの高さを返します
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 68
    }

    // ★ 以下UIMenuControllerをカスタマイズするのに必要
    func tableView(tableView: UITableView, shouldShowMenuForRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
    }

    func tableView(tableView: UITableView, canPerformAction action: Selector, forRowAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject) -> Bool {
        return true
    }

    func tableView(tableView: UITableView, performAction action: Selector, forRowAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject!) {
    }
}

CustomTableViewCell.swift

class CustomTableViewCell: UITableViewCell
{
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }
    
    override func canBecomeFirstResponder() -> Bool {
        return true
    }

    // 必要なメニューのみ表示します
    override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        if action == "remove:" || action == "edit:" || action == "regist:" {
            return true
        } else {
            return false
        }
    }
    
    func remove(sender: AnyObject) {
      // 削除を押したときに呼ばれる
    }

    func edit(sender: AnyObject) {
      // 編集を押したときに呼ばれる
    }

    func regist(sender: AnyObject) {
      // 登録を押したときに呼ばれる
    }
}

こんなかんじでやりたいことができました
ポイントとしてはUITableViewCellをカスタマイズしたクラスを作って
canBecomeFirstResponderメソッドとcanPerformActionメソッドを実装するところですかね

これも知ってると便利そうなのでメモしておきました

以上になります