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 и да върне оформлението на 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 добави персонализирани 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 се появява отдолу, поддържа плъзгане и конфигурируема височина. За разширено поведение с detents се използва 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 препоръчва използването на 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 при отваряне и го връща обратно при затваряне. Персонализираните имплементации изискват ръчна настройка на достъпността.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също