Modal Presentation в мобильной разработке: что это, виды экранов

Автор: IT Sectr Опубликовано: 2026-06-09 Время чтения: 5 мин

Modal Presentation — способ отображения экрана поверх текущего контекста с блокировкой взаимодействия с предыдущим интерфейсом. В мобильной разработке модальные окна используются для фокусных задач: ввод данных, подтверждение действий, авторизация и выбор опций. По данным Apple HIG, 2025, модальные презентации должны занимать не более 20% навигационных сценариев в приложении. В Android модальность реализуется через DialogFragment, BottomSheet и Activity с определёнными launch-флагами.

Главное

  • Modal Presentation — техника показа экрана, блокирующая взаимодействие с предыдущим контентом до закрытия модального окна.
  • iOS использует UIModalPresentationStyle с вариантами .fullScreen, .pageSheet, .formSheet и .automatic.
  • Android реализует модальность через DialogFragment, BottomSheetDialogFragment и Activity с флагами Intent.
  • SwiftUI предоставляет модификаторы .sheet и .fullScreenCover для декларативной модальной презентации.
  • Jetpack Compose использует Dialog и ModalBottomSheet для создания модальных интерфейсов.

Что такое Modal Presentation?

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 PresentationPush Presentation
Блокировка назадДа, требуется явное действиеНет, кнопка назад всегда доступна
Типичное использованиеФормы, авторизация, выборДетальный просмотр, навигация
АнимацияСнизу вверх (iOS), слайд (Android)Справа налево (iOS)
Стек навигацииНе добавляется в основной стекДобавляется в стек

На практике выбор между Modal и Push зависит от контекста. Рекомендуется использовать модальность для задач, которые пользователь должен завершить перед продолжением, и Push — для последовательного изучения контента. Смешивание паттернов на одном экране приводит к путанице и ухудшает UX.

Модальная презентация в iOS: UIKit и SwiftUI

iOS предлагает несколько стилей модальной презентации через перечисление UIModalPresentationStyle. UIKit поддерживает .fullScreen (полный экран), .pageSheet (карточка с отступом сверху), .formSheet (центрированное окно на iPad) и .automatic (выбор системой на основе контекста). Начиная с iOS 13, дефолтным стилем стал .automatic, который для iPhone выбирает .pageSheet.

UIViewController.present

Базовый метод UIKit для модальной презентации — present(_:animated:completion:). Контроллер, вызывающий метод, становится presentingViewController, а новый — presentedViewController. Закрытие выполняется через dismiss(animated:completion:). SwiftUI предоставляет модификатор .sheet для аналогичного поведения.

SwiftUI .sheet

Декларативный подход SwiftUI использует модификаторы .sheet и .fullScreenCover. Первый создаёт Page Sheet, второй — полноэкранную модальную презентацию. Оба принимают binding на Bool или идентифицируемый объект, который управляет видимостью модального окна. Закрытие происходит при установке binding в false или вызове dismiss из environment.

swift
struct ContentView: View {
    @State private var showModal = false

    var body: some View {
        Button("Open Form") {
            showModal = true
        }
        .sheet(isPresented: $showModal) {
            RegistrationForm()
        }
    }
}

struct RegistrationForm: View {
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        Button("Save") { dismiss() }
    }
}

Модальная презентация в Android: Fragment и Compose

Android не имеет единого API для модальной презентации, как iOS. Вместо этого платформа предлагает несколько механизмов: DialogFragment для диалоговых окон, BottomSheetDialogFragment для нижних панелей и Activity с флагами NEW_TASK и CLEAR_TOP для модальных экранов. В Jetpack Compose появился единый компонент Dialog для всех типов модальных окон.

DialogFragment

DialogFragment — базовый класс для модальных окон в Android SDK. Он управляет жизненным циклом диалога, обрабатывает поворот экрана и сохраняет состояние. Фрагмент отображается поверх Activity без блокировки навигационного стека. Закрытие выполняется через dismiss() или нажатие вне области диалога, если setCancelable(true).

Modal Bottom Sheet

BottomSheetDialogFragment отображает модальное окно в виде панели, поднимающейся снизу. Этот паттерн популярен в Material Design для выбора опций, шаринга и быстрых действий. BottomSheet может быть фиксированной высоты или расширяемой (peek height + full height). В Compose используется ModalBottomSheet из библиотеки Material3.

kotlin
@Composable
fun ModalScreen(onDismiss: () -> Unit) {
    Dialog(onDismissRequest = onDismiss) {
        Card(
            modifier = Modifier.padding(16.dp)
        ) {
            Column {
                Text("Modal Form", style = MaterialTheme.typography.headlineSmall)
                Button(onClick = onDismiss) {
                    Text("Close")
                }
            }
        }
    }
}

Лучшие практики модальной презентации

Модальные окна — мощный инструмент UX, но их чрезмерное использование ухудшает пользовательский опыт. Apple HIG и Google Material Design сходятся в рекомендациях: модальность должна применяться для фокусных задач и не превышать 20% от общего числа навигационных действий.

Когда использовать модальную презентацию

Модальные окна подходят для сценариев: ввод данных (формы регистрации, профиля), подтверждение (удаление, отправка), выбор (пикер даты, файловый менеджер) и авторизация (OAuth, Firebase Auth). Если задача занимает менее 30 секунд и требует блокировки контекста — выбирайте модальность.

Чего избегать

Не используйте модальную презентацию для: последовательного просмотра контента (используйте Push), отображения ошибок (используйте Toast или Snackbar), рекламы и промо-предложений без явного запроса пользователя. Material Design рекомендует избегать вложенных модальных окон — это дезориентирует пользователя и нарушает иерархию навигации.

Для модальных окон с текстовыми полями обязательно обрабатывайте потерю фокуса клавиатуры. При появлении клавиатуры модальное окно должно сдвигаться вверх, чтобы пользователь видел вводимый текст. UIKeyboardWillShowNotification в iOS и adjustResize в Android решают эту задачу.

Примеры кода на Swift и Kotlin

Рассмотрим реализацию модальной презентации на обеих платформах. Swift пример показывает настройку UIModalPresentationStyle.pageSheet с делегатом для обработки закрытия. Kotlin пример демонстрирует DialogFragment с кастомным layout и сохранением состояния.

swift
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("Modal dismissed")
    }
}
kotlin
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?

Используйте Modal Presentation для фокусных задач, которые пользователь должен завершить перед продолжением: формы, подтверждения, авторизация. Push подходит для последовательного просмотра контента, где пользователь может свободно возвращаться назад. Модальное окно не должно содержать навигации внутри себя.

Какой стиль модальной презентации выбрать в iOS?

Начиная с iOS 13, дефолтный стиль .automatic выбирает .pageSheet для iPhone. .pageSheet подходит для большинства сценариев (формы, детали). .fullScreen — для медиаконтента (видео, фоторедакторы). .formSheet — для iPad-приложений, где нужно центрированное окно.

Как реализовать модальное окно в Jetpack Compose?

Jetpack Compose предоставляет компонент Dialog для простых модальных окон и ModalBottomSheet для нижних панелей. Dialog принимает onDismissRequest и контент в Compose-стиле. Для сохранения состояния используйте rememberSaveable внутри диалога.

Можно ли вкладывать модальные окна друг в друга?

Apple HIG и Material Design не рекомендуют вложенные модальные окна. Если пользователь открывает модальное окно поверх другого модального окна, он теряет контекст и может запутаться в иерархии. Вместо вложенности используйте Step Indicator или Wizard-паттерн с одним модальным окном.

Как обработать закрытие модального окна при потере данных?

Используйте UIAdaptivePresentationControllerDelegate в iOS (метод presentationControllerShouldDismiss) или OnBackPressedDispatcher в Android. При наличии несохранённых данных показывайте AlertDialog с вариантами: сохранить, отменить изменения, остаться на экране. Это предотвращает случайную потерю данных пользователем.

Итоги

  • Modal Presentation — паттерн навигации, блокирующий взаимодействие с родительским контентом до завершения задачи.
  • iOS поддерживает .fullScreen, .pageSheet, .formSheet через UIModalPresentationStyle и .sheet в SwiftUI.
  • Android реализует модальность через DialogFragment, BottomSheet и Dialog в Jetpack Compose.
  • Modal отличается от Push блокировкой назад и требованием явного действия для закрытия.
  • Модальные окна не должны превышать 20% навигационных сценариев и не должны быть вложенными.
  • Потерю данных при закрытии модального окна нужно предотвращать через делегаты и диалоги подтверждения.
  • Рекомендуется выбирать Page Sheet в iOS и DialogFragment в Android для стандартных модальных задач.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также