Search code examples
iosswiftuibarbuttonitemuimenucontroller

Show UIMenuController from UIBarButtonItem


I have a navigation bar with a bar button item on the right. I would like to open a popup menu when pressing that button.

Can anyone tell why this doesn't work:

@IBAction func quickJumpClicked() {

    let menu = UIMenuController.sharedMenuController()
    menu.menuItems =
        [UIMenuItem(title: "Test me", action: Selector("deleteLine")),
        UIMenuItem(title: "Test me", action: Selector("deleteLine")),
        UIMenuItem(title: "Test me", action: Selector("deleteLine"))]
    menu.setTargetRect(self.navigationController!.toolbar.subviews[1].frame, inView: self.view.superview!)

    becomeFirstResponder()
    menu.setMenuVisible(true, animated: true)
}

Solution

  • I don't think your targetRect is functioning as expected. I'm assuming your objective is to get a menu to appear from the UIBarButtonItem.

    One thing you could do is rewrite your IBAction to include a sender, then just get the frame of the sender – in your case, a UIBarButtonItem.

    That would look something like this:

    @IBAction func quickJumpClicked(sender: AnyObject) {
        let menu = UIMenuController.sharedMenuController()
        menu.menuItems =
            [UIMenuItem(title: "Test me", action: Selector("deleteLine")),
                UIMenuItem(title: "Test me", action: Selector("deleteLine")),
                UIMenuItem(title: "Test me", action: Selector("deleteLine"))]
        menu.setTargetRect(sender.view!!.frame, inView: self.view)
        menu.setMenuVisible(true, animated: true)
        becomeFirstResponder()
    }
    

    You may also be missing two methods. canPerformAction(_:withSender:) enables custom commands in the UI, and canBecomeFirstResponder() allows your controller to become first responder and receive messages from UIMenuController.

    For example:

    override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        if action == Selector("deleteLine") {
            return true
        }
        return false
    }
    
    override func canBecomeFirstResponder() -> Bool {
        return true
    }