Το TopAppBar είναι ένα στοιχείο Material Design που εμφανίζει το επάνω πλαίσιο της εφαρμογής με τίτλο, κουμπί πλοήγησης και πρόσθετες ενέργειες. Στο Jetpack Compose, το TopAppBar υλοποιείται μέσω της συνάρτησης composable TopAppBar από τη βιβλιοθήκη Material. Σύμφωνα με την επίσημη τεκμηρίωση του Android Developers (2025), το TopAppBar υποστηρίζει Material2 και Material3, συμπεριλαμβανομένων προσαρμοστικού ύψους, χρωμάτων και κινούμενων σχεδίων. Το πλαίσιο προσαρμόζεται αυτόματα στη γραμμή κατάστασης του συστήματος και λειτουργεί σωστά με τα Insets. Το TopAppBar χρησιμοποιείται ως κύριο σημείο εισόδου για πλοήγηση και ενέργειες περιβάλλοντος σε εφαρμογές Android.
Βασικά σημεία
TopAppBar είναι μια συνάρτηση composable από τη βιβλιοθήκη Material Design για το Jetpack Compose που υλοποιεί το επάνω πλαίσιο της εφαρμογής (App Bar). Το στοιχείο εμφανίζει τον τίτλο της τρέχουσας οθόνης, το κουμπί πλοήγησης στα αριστερά και πρόσθετες ενέργειες στα δεξιά.
Σε αντίθεση με το κλασικό σύστημα View, η έκδοση Compose του TopAppBar είναι πλήρως δηλωτική: το πλαίσιο επανασχεδιάζεται όταν αλλάζει η κατάσταση και δεν διαχειρίζεται μέσω findViewById. Το TopAppBar χρησιμοποιεί την έννοια του slot API, όπου τα title, navigationIcon και actions μεταβιβάζονται ως lambdas composable. Αυτό επιτρέπει την προσαρμογή οποιουδήποτε στοιχείου του πλαισίου χωρίς κληρονομικότητα.
Σύμφωνα με το Google Material Design (2025), το TopAppBar στο Compose διατίθεται σε τρεις τύπους: CenterAlignedTopAppBar (κεντραρισμένος τίτλος), SmallTopAppBar (τυπικός) και MediumTopAppBar (εκτεταμένος). Κάθε τύπος καθορίζει το ύψος του πλαισίου, το μέγεθος γραμματοσειράς του τίτλου και τη συμπεριφορά κατά την κύλιση. Η κεντραρισμένη παραλλαγή χρησιμοποιείται συχνότερα σε κύριες οθόνες, ενώ το MediumTopAppBar για σελίδες με περιεχόμενο όπου ο τίτλος μειώνεται σταδιακά κατά την κύλιση.
Για τη σωστή λειτουργία του TopAppBar πρέπει να ληφθούν υπόψη τα περιθώρια συστήματος: Insets από το WindowInsetsCompat. Σύμφωνα με τη σύσταση του Android Developers (2025), η κλήση Modifier.statusBarsPadding() ή windowInsetsPadding(WindowInsets.systemBars) αποτρέπει την επικάλυψη του πλαισίου με τη γραμμή κατάστασης.
Το στοιχείο TopAppBar δέχεται μια σειρά υποχρεωτικών και προαιρετικών παραμέτρων. Η κύρια είναι το title, όπου μεταβιβάζεται ένα μπλοκ composable με το κείμενο του τίτλου. Επειδή το title είναι ένα @Composable lambda, μπορεί να εισαχθεί όχι μόνο κείμενο, αλλά και εικονίδιο με κείμενο, γραμμή αναζήτησης ή γραμμή προόδου.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppTopBar() {
TopAppBar(
title = { Text("Κύρια") },
navigationIcon = {
IconButton(onClick = { /* open drawer */ }) {
Icon(
Icons.Filled.Menu,
contentDescription = "Menu"
)
}
},
actions = {
IconButton(onClick = { /* search */ }) {
Icon(Icons.Filled.Search, contentDescription = "Search")
}
}
)
}
Η παράμετρος Modifier επιτρέπει τον ορισμό περιθωρίων, μεγέθους και στοίχισης ολόκληρου του πλαισίου. Μέσω του Modifier.heightIn μπορεί να περιοριστεί το ελάχιστο και μέγιστο ύψος. Η παράμετρος colors δέχεται ένα αντικείμενο TopAppBarColors για την αντικατάσταση των χρωμάτων φόντου, τίτλου και εικονιδίων.
Από προεπιλογή, το TopAppBar χρησιμοποιεί το χρωματικό σχήμα από το τρέχον MaterialTheme. Εάν χρειάζεται προσαρμοσμένη παλέτα, χρησιμοποιήστε το TopAppBarDefaults.smallTopAppBarColors(). Στο Material3, το χρώμα φόντου προσαρμόζεται αυτόματα στο surfaceColor σε ανοιχτό και σκοτεινό θέμα, εξαλείφοντας την ανάγκη χειροκίνητης ρύθμισης.
| Παράμετρος | Τύπος | Περιγραφή |
|---|---|---|
| title | @Composable () -> Unit | Μπλοκ τίτλου πλαισίου |
| navigationIcon | @Composable () -> Unit | Εικονίδιο πλοήγησης (χάμπουργκερ/βέλος) |
| actions | @Composable RowScope.() -> Unit | Μπλοκ ενεργειών στα δεξιά |
| scrollBehavior | TopAppBarScrollBehavior? | Συμπεριφορά κατά την κύλιση |
| colors | TopAppBarColors | Χρωματικό σχήμα πλαισίου |
NavigationIcon είναι ένα μπλοκ composable στο αριστερό μέρος του TopAppBar μέσω του οποίου υλοποιείται η πλοήγηση. Τυπικά σενάρια: άνοιγμα Navigation Drawer (εικονίδιο Menu), επιστροφή στην προηγούμενη οθόνη (εικονίδιο ArrowBack) ή κλείσιμο της τρέχουσας οθόνης (εικονίδιο Close).
Η επιλογή εικονιδίου εξαρτάται από τη θέση της οθόνης στη στοίβα πλοήγησης. Εάν η οθόνη είναι ρίζα — εμφανίζεται το εικονίδιο Menu για το άνοιγμα του Drawer. Εάν η οθόνη είναι ένθετη — το εικονίδιο ArrowBack για επιστροφή. Στο Compose, αυτή η λογική υλοποιείται μέσω του NavController: η τρέχουσα εγγραφή back stack καθορίζει ποιο εικονίδιο θα εμφανιστεί.
Σύμφωνα με τη σύσταση του Material Design (2025), το πλάτος της περιοχής πλοήγησης είναι 48 dp — ο τυπικός στόχος για αλληλεπίδραση αφής. Το εικονίδιο πρέπει να είναι κλικ με οπτική ανάδραση (ripple). Στο Compose, αυτό εξασφαλίζεται με περιτύλιξη σε IconButton με callback onClick που εκκινεί την πλοήγηση.
Κατά τη χρήση του Scaffold, το κουμπί πλοήγησης μπορεί να αντιγράψει το DrawerState που μεταβιβάζεται στο Scaffold, όχι απευθείας στο TopAppBar. Σε αυτήν την περίπτωση, το navigationIcon αναφέρεται στην κατάσταση του Drawer μέσω του rememberDrawerState.
Η παράμετρος actions στο TopAppBar δέχεται ένα μπλοκ composable με περιβάλλον RowScope, επιτρέποντας την τοποθέτηση πολλών εικονιδίων ή κουμπιών δεξιά από τον τίτλο. Κάθε ενέργεια πρέπει να είναι ένα κλικ εικονογραφικό στοιχείο: αναζήτηση, ειδοποιήσεις, ρυθμίσεις, αγαπημένα.
Για υπερχειλισμένες ενέργειες χρησιμοποιείται αναδυόμενο μενού μέσω DropdownMenu. Εάν ο αριθμός ενεργειών υπερβαίνει τις τρεις, οι επιπλέον τοποθετούνται στο OverflowMenu με εικονίδιο MoreVert. Με το πάτημα, ανοίγει η λίστα κρυφών ενεργειών. Το DropdownMenu τοποθετείται αυτόματα σε σχέση με το εικονίδιο.
@Composable
fun TopBarWithOverflow() {
var menuExpanded by remember { mutableStateOf(false) }
TopAppBar(
title = { Text("Προφίλ") },
actions = {
IconButton(onClick = { /* share */ }) {
Icon(Icons.Filled.Share, contentDescription = "Share")
}
Box {
IconButton(onClick = { menuExpanded = true }) {
Icon(Icons.Filled.MoreVert, contentDescription = "More")
}
DropdownMenu(
expanded = menuExpanded,
onDismissRequest = { menuExpanded = false }
) {
DropdownMenuItem(text = { Text("Ρυθμίσεις") }, onClick = { /* navigate */ })
DropdownMenuItem(text = { Text("Σχετικά") }, onClick = { /* navigate */ })
}
}
}
)
}
Είναι σημαντικό να ορίσετε contentDescription για κάθε εικονίδιο — αυτή είναι απαίτηση προσβασιμότητας. Χωρίς περιγραφή, το TalkBack δεν θα εκφωνήσει το κουμπί. Για καθαρά διακοσμητικά στοιχεία, χρησιμοποιήστε contentDescription = null.
Το Material3 (M3) είναι η τρέχουσα έκδοση του Material Design, που συνιστάται από την Google για νέα έργα. Το TopAppBar στο M3 υλοποιείται μέσω TopAppBar, CenterAlignedTopAppBar και MediumTopAppBar. Η βασική διαφορά από το Material2 — η ενσωματωμένη υποστήριξη για dynamic color, προσαρμοστικό ύψος και scroll behavior.
Το Dynamic Color επιλέγει αυτόματα τα χρώματα του πλαισίου βάσει της ταπετσαρίας της συσκευής (Android 12+). Το TopAppBar στο M3 χρησιμοποιεί surfaceColor για φόντο και primary για τίτλο. Εάν το dynamic color δεν είναι διαθέσιμο, εφαρμόζεται η παλέτα εφεδρείας από το MaterialTheme. Σύμφωνα με το Google Material Design (2025), το 63% των χρηστών Android 12+ χρησιμοποιεί dynamic color σε εφαρμογές.
MediumTopAppBar είναι μια εκτεταμένη παραλλαγή με μεγάλο τίτλο (32 sp), ο οποίος κατά την κύλιση μειώνεται σταδιακά σε 20 sp, μετατρεπόμενος σε SmallTopAppBar. Αυτό το εφέ πραγματοποιείται μέσω TopAppBarDefaults.mediumTopAppBarColors() και της παραμέτρου scrollBehavior. Η κινούμενη μετάβαση ελέγχεται από το TopAppBarState που παρακολουθεί τη σύμπτυξη του τίτλου.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MediumTopBarExample() {
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Scaffold(
topBar = {
MediumTopAppBar(
title = { Text("Βιβλιοθήκη") },
navigationIcon = {
IconButton(onClick = { }) {
Icon(Icons.Filled.Menu, contentDescription = "Menu")
}
},
scrollBehavior = scrollBehavior
)
}
) { padding ->
LazyColumn(contentPadding = padding) { /* content */ }
}
}
Για το Material3 TopAppBar πρέπει να χρησιμοποιήσετε @OptIn(ExperimentalMaterial3Api::class) — ο σχολιασμός υποδεικνύει ότι το API μπορεί να αλλάξει σε μελλοντικές εκδόσεις. Από το 2025, το TopAppBar στο M3 παραμένει πειραματικό, αλλά η Google το συνιστά για παραγωγή με κατάλληλη επαλήθευση.
ScrollBehavior είναι ο μηχανισμός που διαχειρίζεται την ορατότητα του TopAppBar κατά την κατακόρυφη κύλιση περιεχομένου. Στο Jetpack Compose, το scrollBehavior επιτρέπει την απόκρυψη ή μείωση του πλαισίου για απελευθέρωση χώρου, κάτι που είναι ιδιαίτερα χρήσιμο σε οθόνες με μεγάλη λίστα περιεχομένου.
Το Material3 προσφέρει τρεις στρατηγικές: enterAlways (το πλαίσιο εμφανίζεται κατά την κύλιση προς τα πάνω και κρύβεται κατά την κύλιση προς τα κάτω), exitUntilCollapsed (το πλαίσιο κρύβεται μόνο μετά την πλήρη σύμπτυξη του τίτλου) και προσαρμοσμένη μέσω υλοποίησης της διεπαφής TopAppBarScrollBehavior. Η πρώτη παραλλαγή είναι κατάλληλη για ροές περιεχομένου, η δεύτερη — για οθόνες με MediumTopAppBar.
Το ScrollBehavior απαιτεί συντονισμό με LazyColumn ή LazyRow μέσω rememberLazyListState(). Η κατάσταση κύλισης μεταβιβάζεται στο TopAppBar μέσω της παραμέτρου scrollBehavior. Το στοιχείο εγγράφεται αυτόματα σε συμβάντα κύλισης και κινεί την ορατότητα του πλαισίου. Σύμφωνα με το Android Developers (2025), το enterAlwaysScrollBehavior είναι η πιο δημοφιλής στρατηγική, που χρησιμοποιείται στο 75% των εφαρμογών με κυλιόμενο TopAppBar.
Για να δημιουργήσετε προσαρμοσμένη συμπεριφορά, κληρονομήστε από το TopAppBarScrollBehavior και παρακάμψτε τις μεθόδους onScroll και onDrag. Η προσαρμοσμένη συμπεριφορά είναι χρήσιμη όταν τα τυπικά σενάρια δεν καλύπτουν τις απαιτήσεις σχεδιασμού — για παράδειγμα, το πλαίσιο πρέπει να κρύβεται μόνο μετά την υπέρβαση ενός συγκεκριμένου ορίου κύλισης.
Από προεπιλογή, το scrollBehavior δεν προσθέτει περιθώριο για περιεχόμενο — το paddingTop πρέπει να οριστεί χειροκίνητα μέσω contentPadding στο Scaffold ή μέσω Modifier.padding στο LazyColumn. Στο MediumTopAppBar, τα περιθώρια υπολογίζονται αυτόματα μέσω TopAppBarState.collapsedFraction.
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
topBar = {
MediumTopAppBar(
title = { Text("Περιεχόμενο") },
scrollBehavior = scrollBehavior
)
}
) { padding ->
LazyColumn(contentPadding = padding) { /* items */ }
}
Το ScrollBehavior είναι διαθέσιμο μόνο στο Material3. Στο Material2, το TopAppBar δεν έχει ενσωματωμένη υποστήριξη για απόκρυψη κατά την κύλιση — για παρόμοια συμπεριφορά απαιτείται χειροκίνητη υλοποίηση μέσω NestedScrollConnection.
Συχνές ερωτήσεις
TopAppBar είναι η υλοποίηση App Bar στο Compose, που λειτουργεί δηλωτικά μέσω συναρτήσεων composable. Το Toolbar είναι ένα στοιχείο View από διάταξη XML. Το TopAppBar προσαρμόζεται αυτόματα στο θέμα Compose, υποστηρίζει slot API και δεν απαιτεί findViewById, σε αντίθεση με το Toolbar που διαχειρίζεται μέσω κώδικα Activity.
Στο Material3, η σκιά απουσιάζει από προεπιλογή — το TopAppBar χρησιμοποιεί χρώμα επιφάνειας (surface) αντί για elevation. Στο Material2, η σκιά αφαιρείται ορίζοντας την παράμετρο elevation = 0.dp. Επιπλέον, μπορείτε να καλέσετε Modifier.shadow(0.dp) για πλήρη απενεργοποίηση.
Μεταβιβάστε ένα μπλοκ composable με TextField στην παράμετρο title. Κατά την ενεργοποίηση αναζήτησης, αποκρύψτε τα navigationIcon και actions μέσω υπό όρους απόδοσης. Αποθηκεύστε την κατάσταση μέσω remember: var isSearching by remember { mutableStateOf(false) }. Όταν isSearching = true, στο title αποδίδεται TextField αντί για Text.
Ναι, μέσω προσαρμοσμένου composable στην παράμετρο title. Αντί για ένα Text, μεταβιβάστε ένα Column με δύο Text: το πρώτο — κύριος τίτλος (semibold), το δεύτερο — υπότιτλος (medium, μικρότερο μέγεθος). Το MediumTopAppBar έχει ενσωματωμένη υποστήριξη για τίτλο δύο γραμμών με κινούμενη σύμπτυξη.
Το TopAppBar δεν λαμβάνει αυτόματα υπόψη τα περιθώρια συστήματος. Πρέπει να εφαρμόσετε Modifier.statusBarsPadding() στο TopAppBar ή να χρησιμοποιήσετε Scaffold που διαχειρίζεται τα WindowInsets. Στο Material3, προστέθηκε η παράμετρος windowInsets για αυτόματη λήψη υπόψη των πεδίων συστήματος.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης