M Saif Ullah
07/12/2024, 10:41 AMM Saif Ullah
07/12/2024, 10:45 AMStylianos Gakis
07/12/2024, 10:58 AMM Saif Ullah
07/12/2024, 11:27 AMNavigationBar {
var selectedItemIndex by remember { mutableIntStateOf(0) }
navigationItems.forEachIndexed { index, item ->
NavigationBarItem(
label = { Text(text = item.title) },
selected = index == selectedItemIndex,
onClick = {
selectedItemIndex = index
onItemClick(item.navRoute)
},
icon = {
Icon(
if (index == selectedItemIndex) item.selectedIcon else item.unSelectedIcon,
contentDescription = null
)
})
}
}
M Saif Ullah
07/12/2024, 11:32 AMval navBackStackEntry by rootNavController.currentBackStackEntryAsState()
val currentRoute = remember(navBackStackEntry) {
GraphRoute.fromRoute(navBackStackEntry?.destination?.route ?: "")
}
But this also doesn't work.Stylianos Gakis
07/12/2024, 12:12 PMThere you go, you do not derive the bottom tab selected from the NavController's current destination, but you got something custom. Follow the linked thread above or just go to https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:navigati[…]va/androidx/navigation/compose/demos/BottomBarNavDemo.kt;l=64 to get a real impl. This has nothing to do with the new type-safe APIs or not using them. To be able to check the route with the new type-safe APIs use this https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:navigati[…]=815?q=hasRoute&ss=androidx%2Fplatform%2Fframeworks%2Fsupport as I linked above too.var selectedItemIndex by remember { mutableIntStateOf(0) }
M Saif Ullah
07/12/2024, 12:40 PMval navBackStackEntry by rootNavController.currentBackStackEntryAsState()
val currentRoute = GraphRoute.fromRoute(navBackStackEntry?.destination?.parent?.route ?: "")
As each BottomBar tab have it's own graph. I'm getting the parent of the current destination and mapping that to GraphRoutes.
I also implemented this helper method to convert the TyepSafe route, which is a string, to Route model class.
companion object {
fun fromRoute(route: String): GraphRoute? {
return GraphRoute::class.sealedSubclasses.firstOrNull {
route.contains(it.qualifiedName.toString())
}?.objectInstance
}
}
Thanks for the help.M Saif Ullah
07/12/2024, 12:53 PMhasRoute
) and that one also works. Don't know which one to use but I'll check if any of them cause unnecessary recompositions.
ThanksStylianos Gakis
07/12/2024, 1:04 PMM Saif Ullah
07/12/2024, 1:27 PMStylianos Gakis
07/12/2024, 1:52 PMcurrentBackStackEntryAsState
will of course change when you navigate, you will get a recomposition there, and the new state will be reflected in the UI. This is just compose working as intended, nothing to be worried of there.M Saif Ullah
07/12/2024, 2:06 PMPremature optimization is the root of all evil.Totally makes sense, I think
currentBackStackEntryAsState
gets triggered for the nested destination changes as well, and that causes the recompositions. But not a problem at this stage.
Will try this with multiple backstacks as well.Stylianos Gakis
07/12/2024, 2:12 PMselected = currentDestination?.hierarchy?.any { it.hasRoute(destination::class) } == true,
will run again, but selected
will be the same as it was before. So the BottomNavigationItem
will not need to recompose itself, since it's gonna be equal to what it was before.
I wouldn't worry about this at all unless you can trace that this is somehow actually slowing your app down.M Saif Ullah
07/12/2024, 2:58 PMI wouldn't worry about this at all unless you can trace that this is somehow actually slowing your app down.Totally agree, nothing like that happening. One last question, do I need to make the selected a composeState??
M Saif Ullah
07/12/2024, 2:59 PM@Composable
fun BottomNavBar(
currentDestination: NavDestination?,
onItemClick: (GraphRoute) -> Unit,
) {
val navigationItems = listOf(
BottomNavBarItem(
false, "Movies", Icons.Filled.Movie, Icons.Outlined.Movie, GraphRoute.MovieList
),
BottomNavBarItem(
false,
"Series",
Icons.Filled.MovieFilter,
Icons.Outlined.MovieFilter,
GraphRoute.SeriesList
),
BottomNavBarItem(
false,
"Favourites",
Icons.Filled.Favorite,
Icons.Filled.FavoriteBorder,
GraphRoute.Favourites
)
)
NavigationBar {
navigationItems.forEachIndexed { index, item ->
val isSelected = currentDestination?.hierarchy?.any {
it.hasRoute(item.navRoute::class)
} == true
NavigationBarItem(
label = { Text(text = item.title) },
selected = isSelected,
onClick = { onItemClick(item.navRoute) },
icon = {
Icon(
if (isSelected) item.selectedIcon else item.unSelectedIcon,
contentDescription = null
)
})
}
}
}
Stylianos Gakis
07/12/2024, 3:07 PMnavigationItems
as a private local value in that file instead so that you do not re-create this list every time you get a new currentDestination. That list seems to never change anyway so it can stay there.M Saif Ullah
07/12/2024, 3:31 PMnavigationItems
to the top level outside the composables.