Another common use of context menus is with table views and collection views. In this episode we will explore adding a menu to a table view cell that allows copying a font or toggling it from a favorites list.
Another common use of context menus is with table views and collection views. Here I have a view controller that lists the fonts available on the system. class FontListViewController: UITableViewController { var fonts: [UIFont]! { didSet { tableView.reloadData() } } override func viewDidLoad() { super.viewDidLoad() tableView.register(UITableViewCell.self, forCellReuseIdentifier: "fontCell") fonts = UIFont.familyNames.compactMap { family in UIFont(name: family, size: 16) } } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { fonts.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "fontCell", for: indexPath) cell.textLabel?.text = fonts[indexPath.row].familyName cell.textLabel?.font = fonts[indexPath.row] return cell } } We can embed this simple view controller in our main view controller using an embed segue. override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { let font = fonts[indexPath.row] return UIContextMenuConfiguration(identifier: id, previewProvider: nil) { _ -> UIMenu? in let copyAction = UIAction(title: "Copy", image: UIImage(named: "doc.on.clipboard"), identifier: nil) { _ in let font = self.fonts[indexPath.row] UIPasteboard.general.string = font.familyName } let menu = UIMenu(title: font.familyName, image: nil, identifier: nil, options: [], children: [copyAction]) return menu } } This looks great. Let's now add a context menu to copy the selected font family name to the paste board. We'll need to implement a method defined by UITableViewDelegate to provide the menu for a given row: override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { } Here we're given the index path as well as the point the user is tapping on, in case that is relevant for the given row. In our case it is not, so we can use the index path to find the font we wish to copy. return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { suggestedActions -> UIMenu? in let font = self.fonts[indexPath.row] let copyAction = UIAction(title: "Copy", image: UIImage(systemName: "doc.on.doc"), identifier: nil, discoverabilityTitle: nil) { action in UIPasteboard.general.string = font.familyName } return UIMenu(title: font.familyName, image: nil, identifier: nil, options: [], children: [copyAction]) } Now we can tap and hold on a row in the tableview and get the action to copy a font family. The approach is similar for collection views. Next let's add the ability to toggle a favorite. First we'll create a rudimentary model: private var favorites: Set<String> = [] Next we'll add the appropriate action based on whether the current font is a favorite or not. let favoriteAction = UIAction(title: "Favorite", image: UIImage(systemName: "heart.fill"), identifier: nil, state: .off) { _ in self.favorites.insert(font.familyName) } let unfavoriteAction = UIAction(title: "Unfavorite", image: UIImage(systemName: "heart.slash.fill"), identifier: nil, state: .on) { _ in self.favorites.remove(font.familyName) } let favAction: UIAction = self.favorites.contains(font.familyName) ? unfavoriteAction : favoriteAction return UIMenu(title: font.familyName, image: nil, identifier: nil, options: [], children: [ copyAction, favAction ]) Note the use of state as either .on or .off. This controls whether the menu item has a checkmark next to it or not.