Modal Presentation — це спосіб відображення екрана поверх поточного контексту з блокуванням взаємодії з попереднім інтерфейсом. У мобільній розробці модальні вікна використовуються для фокусних завдань: введення даних, підтвердження дій, авторизація та вибір опцій. За даними Apple HIG, 2025, модальні презентації мають займати не більше 20% навігаційних сценаріїв у застосунку. В Android модальність реалізується через DialogFragment, BottomSheet та Activity з певними launch-прапорами.
Головне
Modal Presentation — це патерн навігації, за якого новий екран з'являється поверх поточного, тимчасово блокуючи взаємодію з батьківським контентом. Користувач має явно завершити модальне завдання (скасувати, зберегти, закрити), щоб повернутися до попереднього стану.
Модальність вирішує когнітивне завдання: вона фокусує увагу користувача на одній дії без відволікання на решту інтерфейсу. Це критично важливо для форм реєстрації, діалогів підтвердження, вибору файлів та авторизації через сторонні сервіси. Human Interface Guidelines від Apple рекомендують використовувати модальність лише для завдань, які потребують завершення перед продовженням роботи.
На відміну від веб-модальних вікон, мобільна Modal Presentation може бути повноекранною (займає весь екран) або частковою (Page Sheet, Bottom Sheet). Вибір типу залежить від контексту завдання та платформених угод. iOS тяжіє до Page Sheet для більшості сценаріїв, залишаючи Full Screen для відеоплеєрів і фоторедакторів.
Push Presentation (стекова навігація) додає екран у навігаційний стек і автоматично показує кнопку назад. Користувач може повернутися на попередній екран у будь-який момент. Modal Presentation, навпаки, передбачає явне завершення: кнопка назад або відсутня, або закриває модальне вікно, а не повертає на попередній екран.
Основні відмінності між модальною та push-презентацією: Modal Presentation блокує навігацію назад без втрати даних, вимагає дії для закриття (Save, Cancel, Done) і зазвичай представляє окреме завдання. Push Presentation зберігає ієрархію навігації, автоматично додає кнопку повернення та підходить для послідовного перегляду контенту.
| Характеристика | Modal Presentation | Push Presentation |
|---|---|---|
| Блокування назад | Так, потрібна явна дія | Ні, кнопка назад завжди доступна |
| Типове використання | Форми, авторизація, вибір | Детальний перегляд, навігація |
| Анімація | Знизу вгору (iOS), слайд (Android) | Справа наліво (iOS) |
| Стек навігації | Не додається в основний стек | Додається в стек |
На практиці вибір між Modal і Push залежить від контексту. Рекомендується використовувати модальність для завдань, які користувач має завершити перед продовженням, і Push — для послідовного вивчення контенту. Змішування патернів на одному екрані призводить до плутанини та погіршує UX.
iOS пропонує кілька стилів модальної презентації через перелік UIModalPresentationStyle. UIKit підтримує .fullScreen (повний екран), .pageSheet (картка з відступом зверху), .formSheet (центроване вікно на iPad) та .automatic (вибір системою на основі контексту). Починаючи з iOS 13, дефолтним стилем став .automatic, який для iPhone обирає .pageSheet.
Базовий метод UIKit для модальної презентації — present(_:animated:completion:). Контролер, який викликає метод, стає presentingViewController, а новий — presentedViewController. Закриття виконується через dismiss(animated:completion:). SwiftUI надає модифікатор .sheet для аналогічної поведінки.
Декларативний підхід SwiftUI використовує модифікатори .sheet та .fullScreenCover. Перший створює Page Sheet, другий — повноекранну модальну презентацію. Обидва приймають binding на Bool або об'єкт, що ідентифікується, який керує видимістю модального вікна. Закриття відбувається при встановленні binding у false або виклику dismiss з environment.
struct ContentView: View {
@State private var showModal = false
var body: some View {
Button("Відкрити форму") {
showModal = true
}
.sheet(isPresented: $showModal) {
RegistrationForm()
}
}
}
struct RegistrationForm: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
Button("Зберегти") { dismiss() }
}
}Android не має єдиного API для модальної презентації, як iOS. Натомість платформа пропонує кілька механізмів: DialogFragment для діалогових вікон, BottomSheetDialogFragment для нижніх панелей та Activity з прапорами NEW_TASK і CLEAR_TOP для модальних екранів. У Jetpack Compose з'явився єдиний компонент Dialog для всіх типів модальних вікон.
DialogFragment — базовий клас для модальних вікон в Android SDK. Він керує життєвим циклом діалогу, обробляє поворот екрана та зберігає стан. Фрагмент відображається поверх Activity без блокування навігаційного стека. Закриття виконується через dismiss() або натисканням поза областю діалогу, якщо setCancelable(true).
BottomSheetDialogFragment відображає модальне вікно у вигляді панелі, що піднімається знизу. Цей патерн популярний у Material Design для вибору опцій, шерингу та швидких дій. BottomSheet може бути фіксованої висоти або розширюваною (peek height + full height). У Compose використовується ModalBottomSheet із бібліотеки Material3.
@Composable
fun ModalScreen(onDismiss: () -> Unit) {
Dialog(onDismissRequest = onDismiss) {
Card(
modifier = Modifier.padding(16.dp)
) {
Column {
Text("Модальна форма", style = MaterialTheme.typography.headlineSmall)
Button(onClick = onDismiss) {
Text("Закрити")
}
}
}
}
}Модальні вікна — потужний інструмент UX, але їх надмірне використання погіршує користувацький досвід. Apple HIG і Google Material Design сходяться в рекомендаціях: модальність має застосовуватися для фокусних завдань і не перевищувати 20% від загальної кількості навігаційних дій.
Модальні вікна підходять для сценаріїв: введення даних (форми реєстрації, профілю), підтвердження (видалення, надсилання), вибір (пікер дати, файловий менеджер) та авторизація (OAuth, Firebase Auth). Якщо завдання займає менше 30 секунд і потребує блокування контексту — обирайте модальність.
Не використовуйте модальну презентацію для: послідовного перегляду контенту (використовуйте Push), відображення помилок (використовуйте Toast або Snackbar), реклами та промо-пропозицій без явного запиту користувача. Material Design рекомендує уникати вкладених модальних вікон — це дезорієнтує користувача та порушує ієрархію навігації.
Для модальних вікон із текстовими полями обов'язково обробляйте втрату фокуса клавіатури. При появі клавіатури модальне вікно має зсуватися вгору, щоб користувач бачив введений текст. UIKeyboardWillShowNotification в iOS та adjustResize в Android вирішують це завдання.
Розглянемо реалізацію модальної презентації на обох платформах. Swift приклад показує налаштування UIModalPresentationStyle.pageSheet з делегатом для обробки закриття. Kotlin приклад демонструє DialogFragment із кастомним layout і збереженням стану.
let modalVC = ModalViewController()
modalVC.modalPresentationStyle = .pageSheet
if let sheet = modalVC.sheetPresentationController {
sheet.detents = [.medium(), .large()]
sheet.prefersGrabberVisible = true
}
modalVC.presentationController?.delegate = self
present(modalVC, animated: true)
// MARK: - UIAdaptivePresentationControllerDelegate
extension ViewController: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
print("Модальне вікно закрито")
}
}class ModalDialogFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_modal, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById<Button>(R.id.closeButton).setOnClickListener {
dismiss()
}
}
}Часті запитання
Використовуйте Modal Presentation для фокусних завдань, які користувач має завершити перед продовженням: форми, підтвердження, авторизація. Push підходить для послідовного перегляду контенту, де користувач може вільно повертатися назад. Модальне вікно не повинно містити навігації всередині себе.
Починаючи з iOS 13, дефолтний стиль .automatic обирає .pageSheet для iPhone. .pageSheet підходить для більшості сценаріїв (форми, деталі). .fullScreen — для медіаконтенту (відео, фоторедактори). .formSheet — для iPad-застосунків, де потрібне центроване вікно.
Jetpack Compose надає компонент Dialog для простих модальних вікон і ModalBottomSheet для нижніх панелей. Dialog приймає onDismissRequest і контент у Compose-стилі. Для збереження стану використовуйте rememberSaveable всередині діалогу.
Apple HIG і Material Design не рекомендують вкладені модальні вікна. Якщо користувач відкриває модальне вікно поверх іншого модального вікна, він втрачає контекст і може заплутатися в ієрархії. Замість вкладеності використовуйте Step Indicator або Wizard-патерн з одним модальним вікном.
Використовуйте UIAdaptivePresentationControllerDelegate в iOS (метод presentationControllerShouldDismiss) або OnBackPressedDispatcher в Android. За наявності незбережених даних показуйте AlertDialog з варіантами: зберегти, скасувати зміни, залишитися на екрані. Це запобігає випадковій втраті даних користувачем.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також