Context Menus Tutorial for iOS: Getting Started
Learn to enhance your app with context menus, including configuring actions, adding images, nesting submenus, adding custom previews and more. By Keegan Rush.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Context Menus Tutorial for iOS: Getting Started
20 mins
With the official release of iOS 13, we got a new, simple, powerful and clean user interface paradigm — context menus. Context menus replace the standard Peek and Pop interaction used until iOS 12 and take it a step further. When you tap and hold on a supported view, a context menu provides a preview of some content as well as a list of actions. They’re used widely throughout iOS, such as in the Photos app. Tapping and holding a photo presents a context menu like this:
The list of actions is customizable as well as the preview. Tapping the preview will open the photo. You can customize what happens when tapping a preview in your own context menus.
In this tutorial, you’ll build context menus and push them to the limit by:
- Configuring actions.
- Setting images for actions using the new SF Symbols collection.
- Simplifying menus with nested and inline submenus.
- Building better, custom previews with relevant info.
- Adding context menus to each item in a table view.
Exploring Vacation Spots
Context menus are all about making existing content noticeable and easy to access. You’ll add menus to an existing app, Vacation Spots, from another great tutorial: UIStackView Tutorial for iOS: Introducing Stack Views.
Download the sample project using the Download Materials button at the top or bottom of this tutorial, open the begin project in Xcode, run the app and start planning your next holiday. :]
When opening the app, you’ll see a table view with a collection of different destinations.
Tapping a vacation spot shows important information about the destination. You can also add a rating of the spot, view it on the map or go to its Wikipedia page.
Your First Context Menu
Tap the Submit Rating button when viewing a vacation spot.
The app displays a few different buttons representing 1-5 stars. Tap your choice and then Submit Your Rating. The Submit Rating button now changes to Update Rating, along with your chosen score. Tapping it again lets you change or review your rating.
This could become a tedious process for some of the eager world travelers using our app. It’s a great candidate for your first context menu.
Back in Xcode, open SpotInfoViewController.swift, where you’ll add the context menu.
At the bottom of the file, add this extension:
// MARK: - UIContextMenuInteractionDelegate
extension SpotInfoViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(
_ interaction: UIContextMenuInteraction,
configurationForMenuAtLocation location: CGPoint)
-> UIContextMenuConfiguration? {
return UIContextMenuConfiguration(
identifier: nil,
previewProvider: nil,
actionProvider: { _ in
let children: [UIMenuElement] = []
return UIMenu(title: "", children: children)
})
}
}
The UIContextMenuInteractionDelegate
protocol is the key to building context menus. It comes with a single required method — contextMenuInteraction(_:configurationForMenuAtLocation:)
, which you’ve just implemented by creating and returning a new UIContextMenuConfiguration
object.
There’s a lot to go over, but once you’re through, you’ll understand the basics of context menus in iOS. The UIContextMenuConfiguration
initializer takes three arguments:
-
identifier: Use the
identifier
to keep track of multiple context menus. -
previewProvider: A closure that returns a
UIViewController
. If you set this tonil
, the default preview will display for your menu, which is just the view you tapped. You’ll use this later to show a preview that’s more appealing to the eye. -
actionProvider: Each item in a context menu is an action. This closure is where you actually build your menu. You can build a
UIMenu
withUIAction
s and nestedUIMenu
s. The closure takes an array of suggested actions provided by UIKit as an argument. This time, you’ll ignore it as your menu will have your own custom items.
You may have noticed that you never create a context menu directly. Instead, you’ll always create a UIContextMenuConfiguration
object that the system uses to configure the items in the menu.
Generally, the UIMenu
used to create a context menu doesn’t need a title, so you provide it with a blank string. But, so far, this creates an empty menu. It would be much more useful menu if it had some actions in it.
Add this method below contextMenuInteraction(_:configurationForMenuAtLocation:)
:
func makeRemoveRatingAction() -> UIAction {
// 1
var removeRatingAttributes = UIMenuElement.Attributes.destructive
// 2
if currentUserRating == 0 {
removeRatingAttributes.insert(.disabled)
}
// 3
let deleteImage = UIImage(systemName: "delete.left")
// 4
return UIAction(
title: "Remove rating",
image: deleteImage,
identifier: nil,
attributes: removeRatingAttributes) { _ in
self.currentUserRating = 0
}
}
makeRemoveRatingAction()
creates a UIAction
to remove a user’s rating. Later, you’ll add it as the first item in your context menu. Here’s what your code does, step by step:
- An action can have a set of attributes that affect its appearance and behavior. Because this is a delete action, you use the
destructive
menu element attribute. - If
currentUserRating
is 0, it means the user has no rating. There’s nothing to delete, so you add thedisabled
attribute to disable the menu item. - A
UIAction
can have an image, and iOS 13’s SF symbols look particularly good, so you use theUIImage(systemName:)
initializer with a symbol name from the new SF Symbols app. - Create and return a
UIAction
. It doesn’t need an identifier, as you won’t need to refer to it later. Thehandler
closure will fire when the user taps this menu item.
Back in contextMenuInteraction(_:configurationForMenuAtLocation:)
, replace the line declaring the children
variable with:
let removeRating = self.makeRemoveRatingAction()
let children = [removeRating]
This creates the remove rating action and places it in the children
array.
Great work, your context menu has a useful action now!
Next, add the following at the end of viewDidLoad()
:
let interaction = UIContextMenuInteraction(delegate: self)
submitRatingButton.addInteraction(interaction)
To display a context menu when tapping and holding a view, you add a UIContextMenuInteraction
to that view using the `addInteraction` method. This creates an interaction and adds it to submitRatingButton
.
You’re finally ready to see the context menu in action!
Build and run the app. Tap and hold Update Rating. If you’ve already added a rating, you can remove it. If not, the Remove rating menu item is disabled.
It’s a start, but this humble context menu still has a long way to go. You’ve already been over the most important concepts of context menus:
- UIContextMenuInteraction: Adds a context menu to a view.
-
UIContextMenuConfiguration: Builds a
UIMenu
with actions and configures its behavior. -
UIContextMenuInteractionDelegate: Manages the lifecycle of the context menu, such as building the
UIContextMenuConfiguration
.
But what about more aesthetic concerns, like customizing the menu’s appearance?