Present UIMenu

Is it possible to dynamically present a UIMenu from a UIButton or UIBarButtonItem?

With UIAlertController, it was possible to configure it before presentation. It could have an "Add Image" action and if an image has already been added, a "Remove Image" action.

In contrast, UIMenu is fixed and its actions can't be edited before presentation. Modifying the menu just after adding/removing the image can be cumbersome if you have 3-4 such actions that depend on the app state.

Replies

With changes in iOS 14, you can maintain a reference to your own menu and modify its children as necessary. Then you can register for the UIControl.event.menuActionTriggered event to reset the menu with your own updates (which UIButton will copy).

You can also use UIDeferredMenuElement to generate these menus instead, especially if you just need to generate them once and then they remain static afterwards.
How do you get this to work for a UIBarButtonItem (which is not a UIControl)? If I set a primaryAction or set action/target, I lose the immediate popup of the menu.
smartgo,

You can just set the menu property of the UIBarButtonItem instead.


Try something like this:

Code Block
let infoButton = UIButton()
infoButton.showsMenuAsPrimaryAction = true
infoButton.menu = UIMenu(options: .displayInline, children: [])
infoButton.addAction(UIAction { [weak infoButton] (action) in
infoButton?.menu = infoButton?.menu?.replacingChildren([new items go here...])
}, for: .menuActionTriggered)

  • //For the following:  func setupInfoButton() {         if #available(iOS 14.0, *) {             let infoButton = UIButton()             infoButton.showsMenuAsPrimaryAction = true             infoButton.menu = UIMenu(options: .displayInline, children: [])             infoButton.addAction(UIAction { [weak infoButton] (action) in

    //Would our app state related code goes here? Thanks...

                    infoButton?.menu = infoButton?.menu?.replacingChildren([])             },  for: .menuActionTriggered)         }     }

Add a Comment

//For the following: 
 func setupInfoButton() {
        if #available(iOS 14.0, *) {
            let infoButton = UIButton()
            infoButton.showsMenuAsPrimaryAction = true
            infoButton.menu = UIMenu(options: .displayInline, children: [])
            infoButton.addAction(UIAction { [weak infoButton] (action) in

              //Would our app state related code goes here? Thanks...

                infoButton?.menu = infoButton?.menu?.replacingChildren([])
            },  for: .menuActionTriggered)
        }
    }```