BottomNavigation (Material3-də NavigationBar) — tətbiqin üç-beş əsas ekranı arasında naviqasiyanı təmin edən Material Design komponentidir. Jetpack Compose-da aşağı panel NavigationBar və ya BottomNavigation vasitəsilə həyata keçirilir, burada hər bir element ikon və mətn etiketi ilə təmsil olunur. Google Material Design (2025) məlumatlarına görə, BottomNavigation iOS və Android üçün əsas naviqasiya nümunəsi kimi tövsiyə olunur. Panel avtomatik olaraq WindowInsets vasitəsilə sistem naviqasiyasının (Gesture Navigation) hündürlüyünə uyğunlaşır. Material3-də NavigationBar dynamic color, badge və adaptiv boşluqları dəstəkləyir.
Əsas məqamlar
BottomNavigation — üçdən beşə qədər menyu bəndini göstərən aşağı naviqasiya paneli üçün Material Design komponentidir. Jetpack Compose-da BottomNavigation (Material2) və NavigationBar (Material3) composable funksiyaları vasitəsilə həyata keçirilir. Panel ekranın aşağı hissəsində yerləşir və tətbiqin əsas bölmələrinə sürətli girişi təmin edir.
BottomNavigation-ın əsas vəzifəsi ekran səviyyələri arasında əsas naviqasiyanı təşkil etməkdir. Panelin hər bir elementi ayrıca ekranı təmsil edir (Home, Search, Profile). Sıxma əsas ekran sahəsində məzmunu dəyişir. BottomNavigation iç-içə naviqasiya üçün nəzərdə tutulmayıb — bunun üçün yuxarı hissədə vərəqlər (Tabs) istifadə olunur.
Material Design Guidelines (2025) məlumatlarına görə, aşağı panel yalnız tətbiqin istənilən yerindən əlçatan olan bölmələri ehtiva etməlidir. Panelin uşaq ekranlarda (məsələn, təfərrüatlı səhifə açarkən) gizlədilməsi standart təcrübədir. Compose-da BottomNavigation görünürlüyü Scaffold vəziyyəti və ya NavController cari marşrutu əsasında şərti render vasitəsilə idarə olunur.
Material3-də Legacy BottomNavigation əvəzinə NavigationBar istifadə etmək tövsiyə olunur. NavigationBar Dynamic Color, WindowInsets dəstəyi və təkmilləşdirilmiş sıxma animasiyasını ehtiva edir. Google-a görə, NavigationBar perspektivli komponentdir, M2-dən BottomNavigation isə yalnız geriyə uyğunluq üçün qalır.
Hər bir NavigationBar elementi NavigationBarItem composable vasitəsilə həyata keçirilir. Elementin parametrləri: icon (ikon), label (mətn etiketi), selected (seçim vəziyyəti) və onClick (geriyə çağırış). NavigationBarItem avtomatik olaraq seçilmiş rəngi (primary) və aktivləşdirmə zamanı ikon ölçüsünün dəyişmə animasiyasını tətbiq edir.
@Composable
fun BottomNavBar() {
val items = listOf(
Screen.Home,
Screen.Search,
Screen.Profile
)
var selectedItem by remember { mutableIntStateOf(0) }
NavigationBar {
items.forEachIndexed { index, item ->
NavigationBarItem(
icon = { Icon(item.icon, contentDescription = item.label) },
label = { Text(item.label) },
selected = selectedItem == index,
onClick = { selectedItem = index }
)
}
}
}
NavigationBarItem üçün ikonlar seçilmiş vəziyyət üçün Filled, seçilməmiş üçün Outlined olmalıdır. Material Icons hər iki dəsti təqdim edir: Icons.Filled.Home və Icons.Outlined.Home. NavigationBarItem susmaya görə selected üçün filled variantını göstərir. Fərqli göstəriş lazımdırsa, ikonu şərti olaraq ötürün: if (selected) Filled.X else Outlined.X.
Elementin mətn etiketinin uzunluğu — 12 simvoldan (latın əlifbası) və ya 8 simvoldan (kiril əlifbası) çox olmamalıdır. Uzun etiketlər üç nöqtə ilə kəsilir. Etiketlər üçün maxLines = 1 və ellipsis = TextTruncation.Ellipsis istifadə edin. Etiket həmişə tələb olunarsa, alwaysShowLabel = true parametrini qoyun (susmaya görə true).
| Parametr | Tip | Təsvir |
|---|---|---|
| icon | @Composable () -> Unit | Panel elementinin ikonu |
| label | @Composable (() -> Unit)? | Ikon altında mətn etiketi |
| selected | Boolean | Seçilmiş element bayrağı |
| onClick | () -> Unit | Sıxma zamanı geriyə çağırış |
| badge | @Composable (() -> Unit)? | Bildiriş sayı ilə badge |
selectedItem-in birbaşa yenilənməsi naviqasiyanı yönləndirmir — ekranları dəyişmək üçün NavController ilə inteqrasiya lazımdır. Tipik nümunə: NavigationBarItem-də onClick navController.navigate(route) çağırır, selectedItem isə NavController-ın cari marşrutundan müəyyən edilir.
NavController cari back stack-i saxlayır. Panelin hansı elementinin seçildiyini müəyyən etmək üçün cari marşrutu (navController.currentBackStackEntryAsState().value?.destination?.route) elementlərin marşrutları ilə müqayisə edin. Marşrut uyğun gələrsə — element seçilmiş sayılır. Bu vəziyyətin təkrarlanmasını aradan qaldırır.
@Composable
fun MainScreen(navController: NavController) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
Scaffold(
bottomBar = {
NavigationBar {
items.forEach { item ->
NavigationBarItem(
icon = { Icon(item.icon, contentDescription = item.label) },
label = { Text(item.label) },
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
) { /* content */ }
}
navigate() daxilində əsas parametrlər: popUpTo(startDestination) vərəqləri dəyişərkən back stack-in yığılmasının qarşısını alır, launchSingleTop marşrutun yığında təkrarlanmasını istisna edir, restoreState isə vərəqə əvvəlki ziyarətin vəziyyətini bərpa edir. Bu parametrlər olmadan hər sıxma yığında yeni giriş yaradır ki, bu da Geri düyməsinin düzgün işləməməsinə səbəb olur.
Material3 (M3) NavigationBar və NavigationBarItem-i Material2-dən BottomNavigation-ın əvəzi kimi təqdim edir. M3-ün əsas üstünlükləri: Dynamic Color, adaptiv hündürlük, elementin tam eni boyunca ripple animasiyası və sistem naviqasiyasını nəzərə almaq üçün WindowInsets dəstəyi.
Dynamic Color avtomatik olaraq NavigationBar rənglərini cihazın divar kağızı əsasında seçir (Android 12+). Aktiv element primary rənginə, qeyri-aktivlər isə onSurfaceVariant rənginə boyanır. NavigationBar susmaya görə Modifier.navigationBarsPadding() vasitəsilə sistem naviqasiyasının üzərinə qalxır. Əl ilə idarə etmək üçün windowInsets parametrindən istifadə edin.
M3-də NavigationBar avtomatik olaraq aktiv elementin enini animasiya edir — ikon sola sürüşür, etiket genişlənir. Animasiya 300 ms davam edir və standart Compose easing istifadə edir. Bu davranış arzuolunmazdırsa, NavigationBarItem-də alwaysShowLabel = true vasitəsilə etiketi həmişə göstərin.
Rəngləri dəyişdirmək üçün colors parametrində NavigationBarColors ötürün. Susmaya görə NavigationBarDefaults.colors() istifadə olunur, lakin öz rənglərinizi təyin edə bilərsiniz: containerColor (panel fonu), contentColor (ikon rəngi), indicatorColor (aktiv element fonu). M2-də rənglərin BottomNavigationDefaults vasitəsilə təyin edildiyindən fərqli olaraq, M3-də vahid NavColors interfeysi istifadə olunur.
Layihədə M2-dən (androidx.compose.material) BottomNavigation istifadə olunursa, Google M3 NavigationBar-a miqrasiyanı tövsiyə edir. Miqrasiya importların dəyişdirilməsi, parametrlərin yenilənməsi və @OptIn(ExperimentalMaterial3Api::class) əlavə edilməsini əhatə edir. M2-dən BottomNavigation köhnəlmiş hesab olunur və yeni funksiyalar almır.
NavigationBar vəziyyəti cari seçilmiş elementin indeksini saxlayır. Sadə hallarda remember { mutableIntStateOf(0) } istifadə olunur. Lakin istehsal tətbiqləri üçün indeks naviqasiya qrafı ilə sinxronlaşdırılmalıdır, UI-nin lokal vəziyyəti olmamalıdır.
Vəziyyətin idarə edilməsinə əsas yanaşmalar: NavController-based (tövsiyə olunan) və ViewModel-based. Birinci halda selectedItem NavController-ın cari marşrutundan hesablanır. İkinci halda — ViewModel cari ekranı saxlayır, NavigationBarItem isə ViewModel-dən StateFlow oxuyur. NavController-based daha sadədir, ViewModel-based mürəkkəb logikada (avtorizasiya, A/B testləri) daha çox nəzarət verir.
saveState və restoreState istifadə edərkən NavController avtomatik olaraq hər vərəq daxilində LazyColumn və digər komponentlərin vəziyyətini saxlayır və bərpa edir. Bu, scroll mövqeyini saxlamaq üçün ViewModel-ə ehtiyacı aradan qaldırır. Lakin saxlama giriş sahələri üçün tətbiq olunmur — onlar SavedStateHandle və ya ViewModel tələb edir.
Badge — NavigationBarItem ikonunda göstərilən yığcam bildiriş göstəricisidir. Material3-də badge BadgedBox vasitəsilə həyata keçirilir, o ikonu əhatə edir və badge-i yuxarı sağ küncə yerləşdirir. Badge say (bildirişlərin sayı) və ya nöqtə (sadəcə mövcudluq göstəricisi) ehtiva edə bilər.
@Composable
fun HomeItem(unreadCount: Int) {
NavigationBarItem(
icon = {
BadgedBox(badge = {
if (unreadCount > 0) {
Badge { Text(unreadCount.toString()) }
}
}) {
Icon(Icons.Filled.Home, contentDescription = "Ana səhifə")
}
},
label = { Text("Home") },
selected = false,
onClick = { }
)
}
BadgedBox avtomatik olaraq Badge-i uşaq elementin yuxarı sağ küncünə yerləşdirir. Say 99-u keçərsə, Badge “99+” göstərir. Sıfır dəyərində badge-i gizlətmək üçün if (count > 0) şərtindən istifadə edin. Material3-dən Badge susmaya görə error rənginə (qırmızı) və ağ mətnə malikdir. Fərdiləşdirmə BadgeDefaults.colors(containerColor, contentColor) vasitəsilə aparılır.
Material2-də badge mövcud deyildi — onu Canvas vasitəsilə əl ilə çəkmək və ya üçüncü tərəf kitabxanalarından istifadə etmək lazım idi. Material3 bu problemi yerli komponentlə həll etdi. Android Developers (2025) məlumatlarına görə, BadgedBox NavigationBar ilə tətbiqlərin 40%-də istifadə olunur, bunun 60%-i oxunmamış mesajları göstərmək üçündür.
Tez-tez verilən suallar
Material Design 3-dən 5 elementə qədər tövsiyə edir. Üçdən az — məqsədəuyğun deyil (Tabs istifadə etmək daha yaxşıdır). Beşdən çox — etiketlərin oxunaqlılığını pisləşdirir və touch-targeti azaldır. 5-dən çox bölmə tələb olunarsa, Navigation Rail (planşetlər) və ya Drawer istifadə edin.
Panelin göründüyü marşrutların siyahısını müəyyən edin (adətən kök marşrutlar). Scaffold bottomBar-da NavigationBar-ı yalnız currentRoute bottomNavRoutes daxilində olduqda ötürün. Alternativ — bottomBar olmadan iç-içə ekranlar üçün ayrıca qrafla NavHost.
Material3-dən NavigationBar Dynamic Color, BadgedBox, WindowInsets və aktiv elementin animasiyalı enini dəstəkləyir. Material2-dən BottomNavigation bu funksiyaları olmayan köhnə API-dir. Google yeni layihələr üçün NavigationBar istifadə etməyi və mövcud layihələri miqrasiya etməyi tövsiyə edir.
Problem navigate()-də saveState və restoreState-in olmamasıdır. Onlar olmadan NavController əvvəlki vərəqin vəziyyətini saxlamır. LazyColumn, scroll və giriş sahələrini qorumaq üçün NavOptions-da popUpTo(startDestination) { saveState = true } və restoreState = true əlavə edin.
Keçid animasiyası BottomNavigation deyil, NavHost səviyyəsində idarə olunur. Xüsusi animasiyalarla composable(route, enterTransition, exitTransition) əlavə edin. BottomNavigation üçün fading animasiyası (fadeIn + fadeOut) 300ms müddəti ilə tipikdir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun