I want to present a menu from a UIBarButtonItem
, but only if a runtime check succeeds when the button is tapped, otherwise show an alert.
Quick background. I had some older code (pre-UIMenu days) that handled the UIBarButtonItem
with a target/action that would perform the check and then either show an alert or present an action sheet.
I'm trying to update that code to use a UIMenu
instead of an action sheet (UIAlertController
). I know how to create the UIBarButtonItem
with a UIMenu
. That's easy to implement.
What I can't find in any APIs or in any searching here on SO, is how to manually display a UIMenu
.
Here's a rough example of my code that directly shows a menu from the UIBarButtonItem
:
btnAdd = UIBarButtonItem(systemItem: .add, menu: UIMenu(children: [
// An array of UIAction instances for each menu item
]))
That code works just fine but I need to change it so the menu only appears under the right condition. I'm thinking of something like the following but I don't know how to write the line of code that manually displays a UIMenu
.
btnAdd = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addAction))
...
@objc func addAction(_ sender: UIBarButtonItem) {
if someRuntimeCondition == true {
let menu = UIMenu(children: [
// An array of UIAction instances for each menu item
])
??? // How to display menu from sender?
} else {
// Create and display an alert
}
}
I feel like I'm missing something simple and obvious but I just don't see it.
I've reviewed the documentation for UIMenu
, UIBarButtonItem
, UIContextMenuInteraction
, and UIMenuController
(deprecated). None of these seem to provide a way to manually display a menu from a UIBarButtonItem
. I've also looked at a couple of Apple's sample apps.
Any solution needs to work with iOS 15.0+.
I was seconds away from clicking Submit on my question when I found a tricky solution using UIDeferredMenuElement.uncached
. This doesn't answer the question of how to manually display a UIMenu
from a UIBarButtonItem
but this does achieve my ultimate goal of conditionally showing either an alert or a menu when the UIBarButtonItem
is tapped.
btnAdd = UIBarButtonItem(systemItem: .add, menu: UIMenu(children: [
UIDeferredMenuElement.uncached({ [weak self] completion in
if someRuntimeCondition == true {
completion([]) // send back an empty list of menu items
// Show UIAlertController
} else {
let children = [
// An array of UIAction instances for each menu item
]
completion(children) // send back the proper menu items
}
})
]))