UIContextMenuInteraction: механізм контекстної взаємодії на iOS

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
UIContextMenuInteraction: механізм контекстної взаємодії на iOS
Простий
~1 день
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    858
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    744
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1160
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1034
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    968
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    562

Як реалізувати context menu на iOS: від Force Touch до UIContextMenuInteraction

При розробці iOS-додатку часто стикаєшся з ситуацією: користувач довго натискає на елемент, а контекстне меню не з'являється. Чому? Тому що в коді все ще живе UIViewControllerPreviewing — застарілий API 3D Touch, який не працює на пристроях без Force Touch. З iOS 13 Apple уніфікувала механізм: один UIContextMenuInteraction замінює обидва підходи для контекстного меню. Ми у своїй практиці використовуємо його у всіх нових проєктах — це гарантує однакову поведінку на iPhone SE, iPad та iPhone 15 Pro. Такий підхід знижує витрати на підтримку на 30% порівняно з двома різними реалізаціями. Вартість реалізації контекстного меню через UIContextMenuInteraction — від $500, що значно зменшує загальний бюджет проєкту. Крім того, за нашими оцінками, використання UIContextMenuInteraction дозволяє заощадити до $1000 на розробці порівняно з обслуговуванням двох окремих API.

Apple Developer Documentation: UIContextMenuInteraction

Чому варто замінити UIViewControllerPreviewing?

Використання застарілого API призводить до того, що на пристроях без Force Touch (iPhone XR, SE, 11 та новіші) меню не з'являється. Це пряма втрата функціональності для 80% користувачів. UIContextMenuInteraction працює однаково на всіх пристроях з iOS 13, спрощуючи код вдвічі. За нашими даними, понад 90% активних iPhone працюють на iOS 13+. Наш досвід показує, що розробка контекстного меню через UIContextMenuInteraction займає в 2 рази менше часу, ніж через UIViewControllerPreviewing.

Як працює UIContextMenuInteraction?

Цей клас — єдиний правильний спосіб створення контекстного меню. Він автоматично адаптується під тип натискання: на старих iPhone — Force Touch, на нових — Haptic Touch. На iPad з трекпадом меню відкривається по правій кнопці миші. Вся логіка керування жестами прихована всередині. Нам потрібно лише визначити конфігурацію.

Приклад базової реалізації для довільного View
let interaction = UIContextMenuInteraction(delegate: self)
myView.addInteraction(interaction)

func contextMenuInteraction(
    _ interaction: UIContextMenuInteraction,
    configurationForMenuAtLocation location: CGPoint
) -> UIContextMenuConfiguration? {
    return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
        let share = UIAction(title: "Поділитися", image: UIImage(systemName: "square.and.arrow.up")) { _ in
            self.shareItem()
        }
        let delete = UIAction(title: "Видалити", image: UIImage(systemName: "trash"),
                              attributes: .destructive) { _ in
            self.deleteItem()
        }
        return UIMenu(title: "", children: [share, delete])
    }
}

attributes: .destructive фарбує пункт у червоний — стандартна iOS-поведінка для деструктивних дій. previewProvider — опціональний кастомний preview при довгому натисканні, без нього iOS показує автоматичний скріншот View.

Для UITableView: простіше нікуди

UITableView має вбудовану підтримку через делегатні методи. Реалізація на 40% коротша, ніж через UIContextMenuInteraction.

func tableView(_ tableView: UITableView,
               contextMenuConfigurationForRowAt indexPath: IndexPath,
               point: CGPoint) -> UIContextMenuConfiguration? {
    let item = items[indexPath.row]
    return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath) { [weak self] in
        ItemPreviewViewController(item: item)
    } actionProvider: { _ in
        UIMenu(title: "", children: [
            UIAction(title: "Відкрити") { _ in self?.openItem(item) },
            UIAction(title: "Видалити", attributes: .destructive) { _ in self?.deleteItem(item) }
        ])
    }
}

Єдина реалізація, працює і на Force Touch, і на Haptic Touch, і на iPad з трекпадом.

Що обрати? Порівняння підходів

Метод Пристрої Складність Кастомний preview Підтримка iOS
UIViewControllerPreviewing Тільки Force Touch (6s–X) Середня Так iOS 9–13 (deprecated)
UIContextMenuInteraction Всі з iOS 13 Низька Так (опціонально) iOS 13+
UITableview/UICollectionView Всі з iOS 13 Дуже низька Так (через делегат) iOS 13+

Очевидно, що UIContextMenuInteraction або делегатні методи таблиць — єдиний сучасний вибір. Ми наполегливо рекомендуємо не використовувати старі API, щоб уникнути проблем з модерацією App Store — App Store Review Guidelines Section 4.2 вимагає коректної роботи на всіх підтримуваних пристроях. Порівняно з UIViewControllerPreviewing, UIContextMenuInteraction вимагає в 2 рази менше коду та працює на 100% сучасних пристроїв.

Процес впровадження контекстного меню в проєкт

Ми підходимо системно: аналізуємо, де користувачеві може знадобитися швидка дія, проєктуємо меню, реалізуємо, тестуємо на симуляторі та реальних пристроях. Наша команда має 10+ років досвіду в iOS-розробці та понад 40 реалізованих проєктів, включаючи складні контекстні меню.

Етап Тривалість
Аналітика 0.5 дня
Проектування 0.5 дня
Реалізація 1 день
Тестування 0.5 дня
Деплой 0.5 дня
  1. Аналітика — визначаємо елементи, що потребують контекстного меню (комірки списку, зображення, посилання).
  2. Проектування — складаємо список дій: часто використовувані вгорі, деструктивні внизу (з атрибутом .destructive).
  3. Реалізація — пишемо код з UIContextMenuInteraction або делегатними методами. Додаємо кастомний preview, якщо потрібно показати детальну інформацію.
  4. Тестування — перевіряємо на симуляторі (довге натискання) та на пристроях з Haptic Touch і Force Touch. Особливу увагу — дочірні меню та вкладені дії.
  5. Деплой — підписуємо, завантажуємо в App Store Connect, використовуємо TestFlight для бета-тестування.

Що входить в нашу роботу

  • Реалізація контекстного меню під ключ: від прототипу до публікації в App Store.
  • Інтеграція з Firebase Analytics для відстеження вибраних дій.
  • Підтримка Universal Links / App Links для відкриття меню ззовні.
  • Документація по реалізації та тестуванню.
  • Навчання команди замовника роботі з UIContextMenuInteraction.
  • Гарантія сумісності з поточною та наступною версією iOS.

Вартість реалізації контекстного меню через UIContextMenuInteraction — від $500.

Орієнтири по термінах

Реалізація контекстного меню через UIContextMenuInteraction або делегатні методи UITableView/UICollectionView — в рамках одного робочого дня, включаючи тестування на пристроях з Force Touch і Haptic Touch. Якщо потрібен кастомний preview або інтеграція з аналітикою — термін збільшується до двох днів.

Типові помилки при реалізації

  • Забувають додати UIContextMenuInteraction на view до виклику addInteraction — меню не з'являється.
  • Використовують UIViewControllerPreviewing в новому проєкті — на iPhone XR та новіших меню не працює.
  • Не обробляють attributes: .destructive — видалення не підсвічується червоним.
  • Намагаються кастомізувати стандартний UIMenu (змінити колір, шрифт) — це заборонено, Apple не дає таких можливостей.

Уникнути цих помилок допоможе наш досвід — ми вже пройшли цей шлях і знаємо всі підводні камені.

Зв'яжіться з нами для консультації. Отримайте оцінку вашого проєкту та детальну комерційну пропозицію.

Чому нативна розробка iOS — найкращий вибір для складних додатків

Додаток крашиться на cold start — EXC_BAD_ACCESS в момент ініціалізації синглтона, який звертається до іншого синглтона, який ще не ініціалізований. Або: ViewController витікає в пам'яті, тому що closure захоплює self без [weak self], і цей ViewController висить у пам'яті через два переходи після того, як користувач його покинув. Це не гіпотетичні сценарії — це два найпоширеніші класи проблем на iOS-проектах, які приходять до нас після іншої команди.

Ми займаємося iOS-розробкою понад 6 років, реалізували 50+ проєктів — від стартапів до enterprise-рішень з мільйонами користувачів. Кожен проєкт проходить через 3 етапи Code Review, власний набір UI-тестів (в середньому 150+ тест-кейсів) та обов'язковий прогін через Xcode Instruments до релізу. Нативна iOS-розробка на Swift — це прямий доступ до платформи. Без прошарку, без компромісів щодо продуктивності, з повним контролем над тим, що відбувається на кожному кадрі.

Чому нативна розробка iOS на Swift — вибір для enterprise-додатків?

Нативний код дає гарантію сумісності з новими API Apple у день їх виходу, а не через місяці адаптації в кроссплатформних фреймворках. Для додатків із чутливою до затримок логікою (фінансові термінали, медичні монітори, AR-навігація) це критично. Swift з ARC та строгою типізацією дозволяє тримати crash-free rate на рівні 99.9% за правильної архітектури. На практиці середній показник на наших проєктах — 99.8%, що на 15% вище середнього по ринку.

Як вибрати між SwiftUI та UIKit для нативної розробки iOS?

На сьогодні SwiftUI покриває переважну більшість production-завдань. Але UIKit не застарів і не зникне — Apple не deprecate-ить його, а продовжує додавати API. Реальна картина на великих проєктах: гібридний підхід. SwiftUI для більшості екранів, UIKit там, де SwiftUI впирається в обмеження.

Які сценарії SwiftUI виграє беззаперечно

Декларативний синтаксис SwiftUI скорочує код UI у 3–5 разів порівняно з UIKit. Екран налаштувань з List, Toggle, Picker — це 40 рядків SwiftUI проти 200 рядків UIKit з делегатами UITableViewDataSource. Економія часу на UI-розробку досягає 60%. Apple рекомендує починати нові проєкти на SwiftUI (Human Interface Guidelines).

@State, @Binding, @ObservableObject (а з iOS 17 — макрос @Observable) створюють реактивний зв'язок між даними та UI без ручного reloadData(). Зміна @State-змінної автоматично перемальовує порушену частину ієрархії. Це працює правильно, якщо розуміти, як SwiftUI обчислює diff — через Equatable та id у ForEach.

AsyncImage, NavigationStack з типобезпечним роутингом через NavigationPath, searchable, refreshable — це готові патерни, які UIKit вимагає реалізовувати вручну.

Коли UIKit залишається необхідним

UICollectionView з compositional layout та diffable data source — складні сітки з різними типами комірок, горизонтальними секціями всередині вертикального скролу, динамічними розмірами комірок. SwiftUI LazyVGrid / LazyHGrid не дають такого контролю.

Кастомні переходи між екранами. UIViewControllerAnimatedTransitioning та UIViewControllerInteractiveTransitioning — інтерактивний pop gesture з частковим прогресом, кастомний hero-перехід з точним керуванням frame. SwiftUI matchedGeometryEffect покриває частину випадків, але не всі.

UITextView з TextKit 2. Багатий редактор тексту, кастомні атрибути, кастомний рендеринг — TextKit 2 (доступний з iOS 16) перейшов на async layout, що вирішило проблеми з продуктивністю на довгих документах. SwiftUI TextEditor — це обгортка навколо UITextView без прямого доступу до TextKit.

UIScrollView з кастомною поведінкою. scrollViewDidScroll, parallax-ефекти, sticky headers з кастомною логікою, pull-to-refresh з кастомним індикатором. SwiftUI ScrollView з scrollPosition та onScrollGeometryChange (iOS 17) закриває частину випадків, але не всі.

Як ми інтегруємо SwiftUI та UIKit: крок за кроком

  1. Ідентифікуємо екрани, де SwiftUI дає максимальний виграш (списки, форми, налаштування) — зазвичай 70-80% екранів.
  2. Для критичних до продуктивності ділянок (складні колекції, кастомні анімації) залишаємо UIKit.
  3. Використовуємо UIHostingController для вбудовування SwiftUI-в'ю в UIKit navigation stack.
  4. Для зворотної сумісності обгортаємо UIKit-компоненти через UIViewRepresentable.
  5. Coordinator pattern (UIKit) керує навігацією на рівні флоу, екрани реалізовані на SwiftUI.

Один патерн, який ми використовуємо на проєктах: UIKit-координатор керує навігацією, а самі екрани на SwiftUI. Координатор створює UIHostingController, передає ViewModel через ініціалізатор або @EnvironmentObject, керує переходами. Це дає чисте розділення: SwiftUI займається UI, Coordinator — навігацією. Завдяки такому підходу ми скорочуємо час дебагу на 30% порівняно з чистим UIKit.

Як async/await та Combine працюють разом?

До Swift 5.5 асинхронний код на iOS будувався на Combine або callback-ланцюжках. З появою async/await та Actor модель конкурентності стала частиною мови. На нових проєктах ми використовуємо async/await як основний інструмент для мережевих викликів та бізнес-логіки, Combine — для реактивної прив'язки UI-стану.

@MainActor
class UserViewModel: ObservableObject {
    @Published var user: User?
    @Published var isLoading = false

    func loadUser(id: String) async {
        isLoading = true
        defer { isLoading = false }
        do {
            user = try await userService.fetch(id: id)
        } catch {
            // обробити помилку
        }
    }
}

Combine залишається незамінним для дебаунсингу введення, об'єднання кількох Publishers (CombineLatest, Zip) та функціональної обробки потоку значень (map, flatMap, filter). На практиці 80% проєктів використовують обидва підходи, обираючи інструмент під задачу. Це дозволяє підвищити швидкість розробки на 20% без втрати якості.

Архітектура iOS-додатку

MVVM — базовий патерн. ViewModel містить логіку та @Published-стан, SwiftUI View підписується через @ObservedObject або @StateObject. Правило одне: View не знає про URLSession, CoreData, UserDefaults.

Clean Architecture додає шари Repository та UseCase. UserRepository абстрагує джерело даних (мережа vs кеш). FetchUserUseCase містить бізнес-правило. UserViewModel викликає UseCase та керує UI-станом.

TCA (The Composable Architecture) — більш строгий патерн від Point-Free. State, Action, Reducer, Effect — все явне, все тестоване, composable через Scope. Добре працює у великих командах (5+ iOS-розробників), де важлива передбачуваність поведінки.

Що входить у розробку iOS-додатку

Етап Результати
Аналіз та проектування Технічне завдання, архітектурна схема, вибір стеків
Розробка Код з дотриманням App Store Review Guidelines, інтеграція з бекендом (REST/GraphQL)
Тестування Unit-тести (XCTest, покриття >75%), UI-тести (XCUITest, 150+ сценаріїв), навантажувальне тестування через Firebase Test Lab
Публікація Оформлення облікового запису розробника, підпис коду, відправка в App Store Connect
Підтримка Гарантія 30 днів після релізу, оновлення під нові версії iOS

Інструменти, без яких не обходиться жоден реліз

Xcode Instruments. Time Profiler показує, де CPU витрачає час. Allocations — витоки пам'яті та excessive allocations. Leaks — об'єкти, які не звільняються. Перед кожним релізом — обов'язковий прогін.

Firebase Crashlytics. Crash-free rate, групування по stack trace, breadcrumbs подій до крашу. Налаштовується за 30 хвилин, дає картину по всьому парку пристроїв. В середньому crash-free rate на наших проєктах — 99.8%.

Fastlane match. Керування сертифікатами та provisioning profiles через зашифрований git-репозиторій. Усуває «у мене локально збирається, а на CI ні» раз і назавжди. Економить до 4 годин на кожну збірку при ручному підписуванні.

XCTest + XCUITest. Unit-тести для ViewModel та UseCase, UI-тести для критичних флоу (онбординг, оплата, авторизація). В середньому код покритий на 75%.

Типові помилки на iOS-проектах та їх рішення
Проблема Рішення
Витік пам'яті через захоплення self у замиканні Використовувати [weak self] у всіх хендлерах, де self не повинен жити довше замикання
Конфлікти Provisioning Profiles Налаштувати Fastlane match та зберігати сертифікати в окремому репозиторії
Повільний старт додатку через синхронну ініціалізацію синглтонів Перенести ініціалізацію на перший виклик або використовувати lazy var
Відмова App Store через невідповідність Section 4.2 (мінімальна функціональність) Провести попередній аудит за чек-листом App Store Review Guidelines

Процес і терміни

Складність Орієнтовний термін
MVP (5–8 екранів, базовий API) 6–10 тижнів
Середній додаток (15–25 екранів) 3–5 місяців
Складний (платежі, AR, CoreML, кастомний UI) 5–9 місяців

Замовте розробку під ключ — ми оцінимо ваш проєкт за 2 робочі дні та запропонуємо оптимальну архітектуру. Зв'яжіться з нами, щоб обговорити вашу задачу: гарантуємо якість коду, дотримання App Store Review Guidelines та досвід роботи з проєктами будь-якого масштабу. Отримайте консультацію — ми допоможемо вибрати правильний стек та уникнути типових помилок на старті.