Reputation: 411
The official documentation of Compose Navigation component suggests that we should create a Navigation component by adding NavHost inside a Scaffold.
see https://developer.android.com/jetpack/compose/navigation#bottom-nav
The problem that i have with this approach is that with this approach the bottom nav bar will be visible in all the screens. I want it to be visible in just the screens that are present in the bottom bar items.
Second approach of adding bottom bar would be to not add NavHost inside Scaffold. Instead Add Bottom Bar in one of theDestinations, then hide/show Composables from the body of the Scaffold based on the index selected like this.
var selectedBottomBarIndex by remember {
mutableStateOf(0)
}
Scaffold(
bottomBar = {
MyBottomBar(currentIndex = selectedBottomBarIndex, onChanged = {
selectedBottomBarIndex = it
}
)
} {
when (selectedBottomBarIndex) {
0 -> HomeScreen(navController)
1 -> AssignmentHomeScreen(navController)
2 -> CategoryScreen(navController)
else -> ProfileHomeScreen(navController)
}
}
I just want to know what are pros and cons of both the ways of adding bottom navigation. and is the second approach safe to use in a production application.
Upvotes: 2
Views: 4703
Reputation: 4171
Copypast and play in 1 file Tabs.kt
:
package com.example.navigationtest
import android.annotation.SuppressLint
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
data class Profile(val id:String = "user for Profile")
data class Friends (val id:String = "user for Friends")
@Composable
fun FriendsScreen() {
Column{
Text(" FriendsScreen")
Text("World Hello !")
}
}
@Composable
fun ProfileScreen() {
Column{
Text("ProfileScreen")
Text("Hello World!")
}
}
data class TopLevelRoute<String>(val name: String, val route: String, val
icon: ImageVector)
class Icons {
companion object {
val Profile: Int = R.drawable.route_fridge
val Friends: Int = R.drawable.map_pin_blue
}
}
@SuppressLint("RestrictedApi")
@Composable
fun Tabs (){
val topLevelRoutes = listOf(
TopLevelRoute("MyProfile", "Profile",
ImageVector.vectorResource(Icons.Profile)),
TopLevelRoute("MyFriends", "Friends",
ImageVector.vectorResource(Icons.Friends)
)
)
val navController = rememberNavController()
Scaffold(
bottomBar = {
BottomNavigation(modifier = Modifier
.height(70.dp),
backgroundColor = Color(0xffdddddd)
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
topLevelRoutes.forEach { topLevelRoute ->
val isSelected=currentDestination?.hierarchy?.any {
it.hasRoute(topLevelRoute.route,null)
}==true
BottomNavigationItem(
icon = { Icon(topLevelRoute.icon, contentDescription = topLevelRoute.name) },
label = { Text(topLevelRoute.name) },
selected = isSelected ,
onClick = {
navController.navigate(topLevelRoute.route) {
popUpTo(navController.graph.findStartDestination().id) {saveState = true}
launchSingleTop = true
restoreState = true
}
},
selectedContentColor = Color. Blue,
modifier = if(isSelected)
Modifier.background(Color(0xffdddddd))
else
Modifier.background(Color.Gray),
unselectedContentColor = Color.White,
)
}
}
}
) { innerPadding ->
NavHost(navController, startDestination = "Profile", Modifier.padding(innerPadding)) {
composable(route="Profile") { ProfileScreen() }
composable(route="Friends") { FriendsScreen() }
}
}
}
and in Activity's onCreate()
:
setContent(Tabs())
Upvotes: 0
Reputation: 3242
Here is an example of how to achieve it.
@Composable
fun JourneyApp() {
JourneyTheme {
val navController = rememberNavController()
val onBack: () -> Unit = {
navController.popBackStack()
}
val screens = listOf(
Screen.Home,
Screen.Collections,
Screen.UserProfile
)
val showBottomBar = navController
.currentBackStackEntryAsState().value?.destination?.route in screens.map { it.route }
// https://developer.android.com/jetpack/compose/navigation
Scaffold(
bottomBar = {
if (showBottomBar) {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
screens.forEach { screen ->
BottomNavigationItem(
icon = { Icon(imageVector = screen.icon, contentDescription = screen.label) },
label = { Text(screen.label) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.route) {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the back stack as users select items
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true
}
}
)
}
}
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
// nav graph
NavHost(navController = navController, startDestination = Screen.Home.route) {
// add new navigation function
composable(Screen.Home.route) { HomeScreen(navigateToImportPhoto = { navController.navigate("importPhoto") }) }
composable(Screen.Collections.route) { CollectionsScreen() }
composable(Screen.UserProfile.route) { UserProfileScreen() }
// new screen, not part of bottom nav
composable("importPhoto") { ImportPhotoScreen(onBack = onBack) }
}
}
}
}
}
Upvotes: 6