Реализация Context Menu для iOS-приложения
Context Menu в iOS 13+ — это UIMenu + UIContextMenuInteraction. Правильно реализованное контекстное меню одинаково работает при долгом нажатии на Haptic Touch устройствах, при нажатии с усилием на 3D Touch устройствах, и при правом клике на iPad с трекпадом или Magic Mouse.
UIContextMenuInteraction для произвольного View
class CardView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
let interaction = UIContextMenuInteraction(delegate: self)
addInteraction(interaction)
}
}
extension CardView: UIContextMenuInteractionDelegate {
func contextMenuInteraction(
_ interaction: UIContextMenuInteraction,
configurationForMenuAtLocation location: CGPoint
) -> UIContextMenuConfiguration? {
UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { [weak self] _ in
guard let self = self else { return nil }
let open = UIAction(title: "Открыть", image: UIImage(systemName: "arrow.up.right")) { _ in
self.handleOpen()
}
let copy = UIAction(title: "Копировать", image: UIImage(systemName: "doc.on.doc")) { _ in
self.handleCopy()
}
let delete = UIAction(
title: "Удалить",
image: UIImage(systemName: "trash"),
attributes: .destructive
) { _ in
self.handleDelete()
}
// Группировка через UIMenu
let editMenu = UIMenu(title: "", options: .displayInline, children: [copy])
return UIMenu(title: "", children: [open, editMenu, delete])
}
}
}
options: .displayInline для вложенного UIMenu убирает заголовок подгруппы и визуально разделяет пункты горизонтальной линией — стандартный паттерн разделения деструктивных действий от безопасных.
SwiftUI .contextMenu
struct ItemView: View {
var item: Item
var body: some View {
ItemCard(item: item)
.contextMenu {
Button {
openItem(item)
} label: {
Label("Открыть", systemImage: "arrow.up.right")
}
Button(role: .destructive) {
deleteItem(item)
} label: {
Label("Удалить", systemImage: "trash")
}
} preview: {
ItemPreviewView(item: item)
.frame(width: 300, height: 200)
}
}
}
preview: в SwiftUI — preview при долгом нажатии, аналог previewProvider в UIKit. Button(role: .destructive) автоматически окрашивает пункт в красный.
UITableView и UICollectionView
Специализированные методы делегата без необходимости добавлять UIContextMenuInteraction вручную:
// UITableView
func tableView(_ tableView: UITableView,
contextMenuConfigurationForRowAt indexPath: IndexPath,
point: CGPoint) -> UIContextMenuConfiguration? {
// ...
}
// UICollectionView
func collectionView(_ collectionView: UICollectionView,
contextMenuConfigurationForItemsAt indexPaths: [IndexPath],
point: CGPoint) -> UIContextMenuConfiguration? {
// iOS 16+ поддерживает множественный выбор
}
Ориентиры по срокам
Контекстное меню для одного типа View или ячейки — несколько часов. Полноценная реализация для UITableView/UICollectionView с preview и кастомными действиями — 1 рабочий день.







