What’s New in iOS 14's UIMenu and ContextMenu

UIMenu was introduced in iOS 13 to allow easy creation of menus and submenus, which is really handy when building context menus.

iOS 14 brings more customization to UIMenu by introducing out-of-the-box support for UIButton and UIBarButtonItem through the menu property and initializers respectively.

In the following sections, we’ll look at how to set the menu on the above-mentioned UI controls. We’ll also look at the new UIDeferredMenuElement that lets us create dynamic menu items.

Adding UIMenu on UIButton

By assigning the UIMenu to the new menu property on UIButton, UIKit automatically takes care of displaying that menu on a long press.

let destruct = UIAction(title: "Destruct", attributes: .destructive) { _ in }
let items = UIMenu(title: "More", options: .displayInline, children: [
UIAction(title: "Item 1", image: UIImage(systemName: "mic"), handler: { _ in }),
UIAction(title: "Item 2", image: UIImage(systemName: "envelope"), handler: { _ in }),
UIAction(title: "Item 3", image: UIImage(systemName: "flame.fill"), handler: { _ in }),
UIAction(title: "Item 4", image: UIImage(systemName: "video"), state: .on, handler: { _ in })
])
button.menu = UIMenu(title: "", children: [items, destruct])

Notably, setting the displayInline as the option displays the submenu within the parent menu itself.

To show the menu immediately on button tap, we need to set the showsMenuAsPrimaryAction property to true:

button.showsMenuAsPrimaryAction = true

In order to determine if the menu is triggered and perhaps perform some other action, iOS 14 has introduced a new control event for UIButton, namely, menuActionTriggered. We can set it to fire the UIAction handler in the following way:

button.addAction(UIAction(title: "") { _ in print("Hello Menu")},for: .menuActionTriggered)

Adding UIMenu On UIBarButtonItem

Besides providing the menu property to create and display UI menus, the UIBarButtonItem also introduces an initializer wherein you can pass the UIMenu group and primary actions as optional arguments.

The following code shows how to construct UIBarButtonItems with primaryAction and menu initializers:

self.toolbarItems = [
UIBarButtonItem(image: UIImage(systemName: "square.and.arrow.up.fill"), primaryAction: action, menu: items),
.fixedSpace(width:20.0),
UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), menu: menu1),
.flexibleSpace(),
UIBarButtonItem(primaryAction: action)
]

The important difference between UIButton and UIBarButtonItem menu action is that, for the latter, there is no showAsPrimaryAction property. So, if you want the UIBarButtonItem to display the menu immediately on touchdown, don’t set a primaryAction.

iOS 14 UIDeferredMenuElement

UIDeferredMenuElement is a powerful new component introduced in iOS 14 that lets you add menu items in an asynchronous fashion.

In order to so, you provide a standard placeholder menu that gets replaced with the deferred menu elements once it’s loaded.

let deferredMenus = UIMenu(title: "", children: [
UIDeferredMenuElement({ completion in
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
let items = (1...2).map { UIAction(title: "Dynamic Menu Item \($0)") { action in } }
completion([UIMenu(title: "", options: .displayInline, children: items)])
}
})
])
button.menu = deferredMenus

Deferred menus provide a built-in caching mechanism that ensures that subsequent loads of the same instance are faster.

UIDeferredMenuElement is also useful for generating deeply nested menus where the items won’t be displayed until they’re needed.

iOS 14 New ContextMenu Interactions

Context menu interactions were introduced last year as a replacement for the 3D touch menus. iOS 14 bumps it up with two new features:

  • updateVisibleMenu — UIMenu elements are no longer immutable, thereby allowing you to replace their attributes in place, while they’re being displayed. This will certainly help in toggling states within context menus.

  • Customizing appearances by invoking the menuAppearance property on UIContextMenuIteraction instance. This new property lets you set the appearance of the context menu as rich or compact, with the former being for displaying previews and the latter being the default look that we’ve seen in the previous sections.

Closing Thoughts

The revamped UIMenus will now be supported on Apple’s own applications for most UI controls. For instance, the options button, on the toolbar in the Safari app, now displays the above compact context menu instead of the old UI action sheet.

The UIMenus will help perform rapid navigation from the back button as well.

The updates Apple has brought to UIKit this year clearly showcase that the framework is here to stay. For a few more years at least.

That’s it for this one. Thanks for reading.