Το Sheet είναι ένα στοιχείο διεπαφής που εμφανίζεται στο κάτω μέρος της οθόνης πάνω από το κύριο περιεχόμενο και παρέχει πρόσθετες ενέργειες ή πληροφορίες. Το Bottom Sheet είναι ο πιο διαδεδομένος τύπος, που ορίζεται στις οδηγίες του Material Design 3 (Google, 2024). Σε αντίθεση με τα παράθυρα διαλόγου, το Sheet δεν μπλοκάρει εντελώς την αλληλεπίδραση με το φόντο και υποστηρίζει τις καταστάσεις collapsed και expanded. Η κατανόηση των τύπων και της συμπεριφοράς του Sheet είναι απαραίτητη για τη δημιουργία βολικής πλοήγησης σε εφαρμογές κινητών.
Βασικά Σημεία
Το Sheet είναι ένα επιφανειακό στοιχείο διεπαφής που αναδύεται από το κάτω μέρος της οθόνης και εμφανίζει πρόσθετο περιεχόμενο ή ενέργειες χωρίς να απομακρύνει τον χρήστη από την τρέχουσα οθόνη. Σε αντίθεση με τις μεταβάσεις πλήρους οθόνης, το 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 χρησιμοποιούν ακριβώς αυτό το εκτεταμένο 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 χειροκίνητα μέσω προσαρμοσμένων μεταβάσεων ή βιβλιοθηκών τρίτων. Το εγγενές 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])
}
}
}
Τα cross-platform πλαίσια υποστηρίζουν επίσης το 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). Παρέχει ένα Bottom Sheet με χειρονομίες που υποστηρίζει snap points, κινήσεις και σταθερές κεφαλίδες. Η βιβλιοθήκη είναι γραμμένη σε Reanimated 2 και Gesture Handler για απόδοση 60 καρέ ανά δευτερόλεπτο.
Η σωστή χρήση του 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 (2024) τονίζουν ότι το σύρσιμο για κλείσιμο είναι βασική προσδοκία των χρηστών iOS.
Συχνές Ερωτήσεις
Το Bottom Sheet δεν μπλοκάρει εντελώς το φόντο και υποστηρίζει σύρσιμο, ενώ το παράθυρο διαλόγου είναι τροπικό και απαιτεί υποχρεωτική ενέργεια. Το Bottom Sheet είναι καλύτερο για πρόσθετες επιλογές, το παράθυρο διαλόγου για κρίσιμες επιβεβαιώσεις.
Ναι, αλλά απαιτείται ρύθμιση adjustResize ή adjustPan στο Android manifest. Στο 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. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης