Sheet — это UI-компонент, который появляется в нижней части экрана поверх основного контента и предоставляет дополнительные действия или информацию. Bottom Sheet — наиболее распространённый вид, определённый в гайдлайнах Material Design 3 (Google, 2024). В отличие от диалоговых окон, Sheet не блокирует полностью взаимодействие с фоном и поддерживает состояния collapsed и expanded. Понимание типов и поведения Sheet необходимо для построения удобной навигации в мобильных приложениях.
Главное
Sheet — это поверхностный UI-компонент, который выезжает снизу экрана и отображает дополнительный контент или действия, не уводя пользователя с текущего экрана. В отличие от полноэкранных переходов, Sheet сохраняет контекст: пользователь видит фоновый экран и понимает, откуда появился Sheet.
Архитектура Sheet основана на контейнере с изменяемой высотой. В минимальном состоянии (collapsed) видна только часть контента — обычно заголовок или небольшая панель. Пользователь может потянуть Sheet вверх, чтобы развернуть его (expanded), или смахнуть вниз, чтобы закрыть. Такое поведение напоминает физический лист бумаги, который выдвигают из-под стопки — отсюда и название.
Google в гайдлайнах Material Design 3 (2024) выделяет два ключевых сценария использования Sheet: отображение дополнительных действий, которые не поместились на основной панели инструментов, и показ форм или детальной информации без перехода на отдельный экран. На iOS Apple добавила системную поддержку Sheet начиная с iOS 15 через UISheetPresentationController, что подтверждает универсальность паттерна.
Material Design определяет три типа Bottom Sheet, каждый со своим поведением и областью применения. Выбор правильного типа напрямую влияет на пользовательский опыт и соответствие гайдлайнам платформы.
Стандартный Bottom Sheet — немодальный компонент: пользователь может взаимодействовать с фоновым экраном, не закрывая Sheet. Например, листая список товаров в фоновом окне, пользователь видит фильтры в Bottom Sheet и может изменять их без закрытия панели. Sheet подстраивает свою высоту под контент — от 30% до 90% экрана.
Стандартный Bottom Sheet не блокирует фон и позволяет взаимодействовать с основным контентом. Это ключевое отличие от модального Sheet, который требует обязательного действия для продолжения работы. Используйте стандартный Sheet, когда дополнительная информация не критична для основного сценария.
Модальный Bottom Sheet блокирует взаимодействие с фоновым экраном, пока пользователь не выполнит действие внутри Sheet. Такой Sheet всегда показывается в expanded-состоянии и требует явного закрытия — через кнопку, действие или свайп вниз. Material Design рекомендует модальный Sheet для форм входа, подтверждений и критичных настроек.
На Android модальный Bottom Sheet реализуется через BottomSheetDialogFragment, который автоматически блокирует фон. На iOS аналогичное поведение обеспечивает модальный вариант UISheetPresentationController с параметром .mediumDetent. Модальный Sheet следует использовать только тогда, когда контекст требует внимания пользователя.
Расширенный Bottom Sheet комбинирует свойства стандартного и модального: он начинается как немодальный в collapsed-состоянии, но при перетаскивании вверх становится модальным. На практике это означает, что пользователь может сначала мельком взглянуть на содержимое, а затем принять решение — развернуть Sheet для детального изучения или закрыть.
Этот паттерн особенно популярен в картах и навигаторах, где нижняя панель показывает краткую информацию о точке маршрута, а при свайпе вверх раскрывается с деталями. Google Maps использует именно такой расширенный Sheet для отображения информации о местах и маршрутах.
| Тип Sheet | Блокировка фона | Начальное состояние | Пример |
|---|---|---|---|
| Стандартный | Нет | Collapsed | Фильтры в каталоге |
| Модальный | Да | Expanded | Форма входа |
| Расширенный | Частично | Collapsed | Карточка места |
Android SDK предоставляет несколько API для реализации Bottom Sheet, начиная от классического View-подхода и заканчивая современным Jetpack Compose. Material Components Library для Android включает готовые реализации BottomSheetDialogFragment и BottomSheetBehavior.
BottomSheetBehavior — это класс из Material Components, который прикрепляется к любой View и управляет её положением на экране. Разработчик задаёт три состояния: STATE_COLLAPSED (свёрнуто), STATE_EXPANDED (развёрнуто) и STATE_HIDDEN (скрыто). Behavior автоматически обрабатывает жесты перетаскивания и анимацию.
val sheet = findViewById<View>(R.id.bottom_sheet)
val behavior = BottomSheetBehavior.from(sheet)
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
behavior.peekHeight = 200
Jetpack Compose предоставляет более декларативный API через компонент ModalBottomSheet из Material 3. В отличие от View-подхода, в Compose Bottom Sheet является composable-функцией, принимающей состояние и контент. Sheet автоматически анимирует появление, скрытие и изменение высоты при перетаскивании.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FilterSheet(onDismiss: () -> Unit) {
ModalBottomSheet(onDismissRequest = onDismiss) {
Text("Filters")
Button(onClick = onDismiss) { Text("Apply") }
}
}
BottomSheetDialogFragment — это специализированный DialogFragment, который отображается как Bottom Sheet. Он автоматически обрабатывает модальность, жизненный цикл и конфигурационные изменения. Разработчику нужно только переопределить onCreateView и вернуть layout Sheet. По данным документации Google (Android Developers, 2024), BottomSheetDialogFragment — рекомендуемый способ для модальных Bottom Sheet в классическом Android.
Apple ввела системную поддержку Sheet начиная с iOS 15 через UISheetPresentationController. До этого разработчики реализовывали Bottom Sheet вручную через custom transition или сторонние библиотеки. Нативный Sheet от Apple поддерживает detents — предопределённые уровни раскрытия.
UISheetPresentationController — это встроенный контроллер презентации, который отображает View Controller как Sheet. Разработчик задаёт массив detents — значений высоты, на которых Sheet может остановиться. iOS 16 добавила custom detents с произвольной высотой. Apple рекомендует использовать medium (.medium) и large (.large) detents как основные.
let viewController = MySheetViewController()
if let sheet = viewController.sheetPresentationController {
sheet.detents = [.medium, .large]
sheet.prefersGrabberVisible = true
sheet.preferredCornerRadius = 16
}
present(viewController, animated: true)
SwiftUI предоставляет модификатор .sheet, который привязывает отображение Sheet к состоянию. Когда published-переменная становится true, SwiftUI автоматически показывает Sheet. SwiftUI также поддерживает detents через модификатор .presentationDetents, добавленный в iOS 16.
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Button("Show Sheet") { showSheet = true }
.sheet(isPresented: $showSheet) {
FilterView()
.presentationDetents([.medium, .large])
}
}
}
Кросс-платформенные фреймворки также поддерживают Bottom Sheet, адаптируя поведение под целевую платформу. Flutter и React Native предоставляют встроенные и кастомные реализации с разной степенью гибкости.
Flutter SDK содержит два метода для отображения Bottom Sheet: showBottomSheet (стандартный) и showModalBottomSheet (модальный). Material Design во Flutter следует тем же принципам, что и в Android — Sheet появляется снизу, поддерживает перетаскивание и настраиваемую высоту. Для расширенного поведения с детектами используется DraggableScrollableSheet.
Scaffold.of(context).showBottomSheet((context) {
return Container(
padding: EdgeInsets.all(16),
child: Column(
children: [
Text("Sheet Content"),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("Close")
)
]
)
);
})
React Native не имеет встроенного Bottom Sheet компонента в ядре, поэтому разработчики используют сторонние библиотеки. Наиболее популярная — @gorhom/bottom-sheet (более 7 тысяч звёзд на GitHub, 2024). Она предоставляет gesture-driven Bottom Sheet с поддержкой snap points, анимаций и закреплённых заголовков. Библиотека написана на Reanimated 2 и Gesture Handler для производительности на 60 FPS.
Правильное использование Bottom Sheet требует соблюдения гайдлайнов платформы и понимания сценариев, в которых Sheet уместен. Рассмотрим ключевые рекомендации и распространённые ошибки при проектировании Sheet.
Bottom Sheet оптимален для действий, которые являются дополнительными по отношению к основному контенту на экране. Фильтры, сортировка, выбор опций, краткая информация о элементе — типичные сценарии. Material Design рекомендует использовать Bottom Sheet для инструментов, которые не должны занимать весь экран, но требуют больше места, чем Action Sheet или Popup Menu.
Не используйте Bottom Sheet для критичных предупреждений или ошибок — для этого подходят диалоговые окна. Избегайте Sheet с большим количеством полей ввода, которые требуют скролла: пользователь с трудом добирается до клавиатуры и теряет контекст. Если Sheet содержит более семи элементов действий, рассмотрите отдельный экран вместо Sheet.
Типичная ошибка — установка peekHeight (высота в свёрнутом состоянии) более 40% экрана. Пользователь не понимает, видит ли он Sheet целиком или его можно развернуть. Material Design рекомендует peekHeight в пределах 15-30% высоты экрана, чтобы оставить заметную часть контента скрытой и мотивировать на перетаскивание.
На iOS пользователи ожидают, что Sheet можно закрыть свайпом вниз из любого положения. Если вы отключаете этот жест (через UISheetPresentationController.prefersEdgeAttachedInCompactHeight), пользователь испытывает фрустрацию, пытаясь закрыть Sheet привычным способом. Apple Human Interface Guidelines (2024) подчёркивают, что свайп для закрытия — базовое ожидание пользователя iOS.
Часто задаваемые вопросы
Bottom Sheet не блокирует фон полностью и поддерживает перетаскивание, а диалоговое окно модально и требует обязательного действия. Bottom Sheet лучше подходит для дополнительных опций, диалог — для критичных подтверждений.
Да, но требуется настройка adjustResize или adjustPan в манифесте Android. На iOS клавиатура автоматически поднимает Sheet. Flutter и React Native требуют ручной обработки через MediaQuery для корректного позиционирования.
Рекомендуется не более 5-7 элементов в стандартном Sheet. Если контента больше — используйте скролл или разбивку на категории. Material Design советует не превышать 90% высоты экрана в expanded-состоянии.
Для модального Sheet установите setCancelable(true) на Android или isModalInPresentation = false на iOS. В Jetpack Compose onDismissRequest автоматически обрабатывает тап по фону. В SwiftUI свайп вниз — стандартное поведение.
Да, все нативные реализации поддерживают VoiceOver и TalkBack. Убедитесь, что FocusManager корректно перемещает фокус в Sheet при его открытии и возвращает обратно при закрытии. Кастомные реализации требуют ручной настройки accessibility.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также