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("Фільтри")
Button(onClick = onDismiss) { Text("Застосувати") }
}
}
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("Показати 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"),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("Закрити")
)
]
)
);
})
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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також