Context Menus are (typically) small menus attached to specific elements of our user interface and that provide context specific functionality. We probably won’t want too many of these but, properly placed, they can greatly enhance our UI.
For the purposes of this article, I will use the same demo project that I used in the article on menus with a few modifications.
The Data
To illustrate the context menu, we will need some data to display in a simple UI. The app will display a list of names.
To achieve this, we're going to need a little sample data and a couple of enums. We'll define these in a single file called UserData.swift.
Our user is simple and consists of a first and last name. I'm going to want to display it in a list and will want to be able to select an item, so it implements Identifiable and Hashable. I want the format of a user to change depending on how the list has been sorted; hence the description function.
I'm going to want to sort the list, so have defined an OrderBy enum. I'll want to use this to construct a Picker for use as a sub-menu, so the Enum needs to conform to Identifiable and CaseIterable. I am also conforming to CustomStringConvertible which requires that I implement a description computed variable.
Finally, we have our data source which defines a published array of users and a helper function to return the array in sorted order.
That's the data dealt with. We now need a way to display it.
Initial Name List Display
Our first pass at the display code will not include the context menu yet. The first thing we need to achieve is the list containing the names.
Firstly, we create an instance of the UserData data source. Next a variable to bind to the list to keep track of the selected user and lastly the current sort order. This is the entire state for our list.
We have a helper variable called nameList that we connect the List to. This deals with calling the userList function of our data source to retrieve the data in the correct order.
Our view consists of a simple List, based on the list of users in sorted order.
I want three context menu items;
- An option to duplicate the currently selected item.
- An option to delete the currently selected item.
- An option to sort the list by first name or last name.
We can attach our context menu to two points in the code. Either the list itself or the individual rows in the list. Attaching to the rows gives us the option to have different menu items depending on which name is being displayed. That's unnecessary in this simple example, so we will add our context menu to the list itself.
The context menu is defined using the .contextMenu modifier. Within that, we define the content of the menu that we want. Here we have defined a Button to duplicate, a Picker to select the sort order and a second Button to delete the current item. There are helper functions to deal with the logic of duplication and deletion.
Running this, selecting an item in the list and right clicking gives us the context menu.
Moving down to the Order By menu expands the menu out to show the ordering options.
Selecting order by last name reorders our list using the last name and changes the way names are displayed to show last name, first name.
Our context menu can be displayed by right clicking anywhere on the list, even in blank space. If we wanted to ensure that the menu only appears when we right click on a name, it would have to be attached to the Text view within the List.
We have also coded the context menu to disable options that are not appropriate if nothing is selected, stopping you from duplicating or deleting items if there is no current selection.
Get The Code