I am using a Bottom Navigation Bar and each menu navigates the user to a specific composable screen. I've used the navigation library to manage the navigation between them.
I am using a common ViewModel for all the composables. I am using a lazy column in one of the composables and when I navigate between the menu items by clicking on them in the Bottom Navigation bar, then it works as expected where in the scroll position of the lazy column is being saved.
The problem occurs when I click the button(which I have programmed to navigate to the start destination in the navigation graph) while in the composable screen that has a lazyColumn and navigate back to it then the scroll position is refreshed to 0. Is this a bug or am I doing something wrong
Here is my code:
The Navigation
@Composable
fun PopulateHomeComposables(navController: NavHostController,
homeViewModel: HomeViewModel, lifecycleScope : LifecycleCoroutineScope) {
NavHost(navController = navController, startDestination =
WHATS_NEW_COMPOSABLE) {
composable(WHATS_NEW_COMPOSABLE) {
WhatsNewComposable(navController)
}
composable(COMPLIMENTS_COMPOSABLE) {
ComplimentsComposable(navController)
}
composable(INSIGHTS_COMPOSABLE) {
InsightsComposable(navController)
}
composable(NOTIFICATIONS_COMPOSABLE) {
NotificationsComposable(homeViewModel, lifecycleScope)
}
}
}
And my Scaffold looks like this
Scaffold(
topBar = {
},
content = {
},
floatingActionButton = {
},
bottomBar = {
val items = listOf(BottomNavScreens.WhatsNew,
BottomNavScreens.Compliments, BottomNavScreens.Insights,
BottomNavScreens.Notifications)
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
//draw the menu items for each one
items.forEach {
BottomNavigationItem(
icon = {
Icon(it.icon, it.label)
},
label = {
Text(it.label)
},
alwaysShowLabel = true,
selected = currentRoute == it.route,
onClick = {
navController.navigate(it.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
navController.graph.startDestinationRoute?.let { route ->
popUpTo(route) {
saveState = true
}
}
//Avoid multiple copies of the same estination when
//re selecting the same item
launchSingleTop = true
//Restore state when re selecting a previously selected item
restoreState = true
}
}
)
}
}
}
)
So i solved this. Since I was using the navigation library, I expected it to take care of saving the composable state when back button is clicked while using the bottomNavBar. But all I had to do was override the back button press inside a composable and add a function to navigate to the start destination using the navHostController.
//override the back button press to navigate back to the
//whatsNewComposable
BackHandler {
Timber.i("Back button clicked in notifications composable")
navController.navigate("myStartDestinationRoute) {
// 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
navController.graph.startDestinationRoute?.let { route ->
popUpTo(route) {
saveState = true
}
}
//Avoid multiple copies of the same destination when
//re selecting the same item
launchSingleTop = true
//Restore state when re selecting a previously selected item
restoreState = true
}