Jetpack Compose - Animating navigation without animating scaffolding topBar and bottomBar

923 Views Asked by At

While trying to work with Accompanist's navigation animation tools, I was pretty content with how the animations turned out, but I wanted the top and bottom bars of the screens to not animate along with the content in the middle. Here's the app in action. As you can see from the gif, the top and bottom bars animate along with the content in the middle, and I would wish for that to not happen, and instead have the content be animated while the top and bottom bars remains static.

Here's the code for one of the 3 navigation screens, as all three screens have roughly the same layout.

@Composable
fun LogScreen(
    OpenTeacherScreen: (String, String) -> Unit,
    OpenSettingsScreen: (String, String) -> Unit,
    modifier: Modifier = Modifier,
    viewModel: LoginViewModel = hiltViewModel()
) {
        val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
        Scaffold(
            scaffoldState = scaffoldState,
            topBar = { TopAppBar(
                title = {
                    Text(text = "BrahmaPass",
                        fontSize = 30.sp,
                        fontFamily = poppinsFamily,
                        fontWeight = FontWeight.Bold,
                        textAlign = TextAlign.Center,
                        modifier = Modifier.fillMaxWidth())},
                backgroundColor = MaterialTheme.colors.primary
            )  },
            content = { padding ->
                Column(
                    horizontalAlignment = Alignment.CenterHorizontally,
                    modifier = Modifier
                        .padding(15.dp)
                        .fillMaxSize()
                ){
                    Text("Exit Log",
                        fontSize = 30.sp,
                        fontFamily = com.example.brahmapassv3.screens.home.poppinsFamily,
                        fontWeight = FontWeight.Medium,
                        textAlign = TextAlign.Center,) }
                },
            bottomBar = { BottomBar(OpenTeacherScreen, OpenSettingsScreen) })
}

@Composable
fun BottomBar(
    OpenTeacherScreen: (String, String) -> Unit,
    OpenSettingsScreen: (String, String) -> Unit,
) {
    val selectedIndex = remember { mutableStateOf(2) }
    BottomNavigation(elevation = 10.dp) {

        BottomNavigationItem(icon = {
            Icon(imageVector = Icons.Default.Settings,"")
        },
            selected = (selectedIndex.value == 0),
            onClick = {
                selectedIndex.value = 0
                OpenTeacherScreen(SETTINGS_SCREEN, LOG_SCREEN)
            })

        BottomNavigationItem(icon = {
            Icon(imageVector = Icons.Default.Home,"")
        },
            selected = (selectedIndex.value == 1),
            onClick = {
                selectedIndex.value = 1
                OpenSettingsScreen(TEACHER_SCREEN, LOG_SCREEN)
            })

        BottomNavigationItem(icon = {
            Icon(imageVector = Icons.Default.DateRange,"")
        },
            selected = (selectedIndex.value == 2),
            onClick = {
                selectedIndex.value = 2
            })
    }
}

And here's the code for the NavGraph composable of this said screen.

composable(
        LOG_SCREEN,
        enterTransition = {
            slideInHorizontally(initialOffsetX = { 1000 })
        })
    {
        LogScreen(
            OpenTeacherScreen = { route, popUp -> appState.navigateAndPopUp(route, popUp) },
            OpenSettingsScreen = { route, popUp -> appState.navigateAndPopUp(route, popUp) }
        )
    }
1

There are 1 best solutions below

0
Sarthak Kadariya On

If all three screens of your app is using same TopAppBar then create a MainScreen with scaffold with defined bottom app bar where navigation bar is and top bar and put Navigation composable inside content

Now you dont need to define top bar and bottom bar for every screen and when you navigate only sreen will animate not the topBar and bottomBar

    @Composable
    fun MainScreen() {
    val navController = rememberNavController()
    val context = LocalContext.current
    val mainScreenViewModel = MainScreenViewModel(context)
    Scaffold(
        contentWindowInsets = ScaffoldDefaults
            .contentWindowInsets.exclude(WindowInsets.statusBars),
        bottomBar = { BottomNavBar(navController = navController) },

        ) {

        MainNavigation(navController, modifier = 
        Modifier.padding(it),mainScreenViewModel)

    }

}


`enter code here`@OptIn(ExperimentalLayoutApi::class)
@Composable
fun BottomNavBar(navController: NavHostController) {
    val screens =
        listOf(MainScreens.HomeScreen, MainScreens.CameraScreen, MainScreens.ProfileScreen)
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentDestination = navBackStackEntry?.destination
    val bottomBarDestination = screens.any { it.route == currentDestination?.route }
    if (bottomBarDestination) {
        NavigationBar(
        ) {

            screens.forEach { screen ->
                NavigationBarItem(
                    icon = { Icon(imageVector = screen.icon, contentDescription = screen.name) },
                    selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
                    onClick = {
                        navController.navigate(screen.route) {

                            popUpTo(navController.graph.findStartDestination().id) {
                                saveState = true
                            }
                            launchSingleTop = true
                            restoreState = true
                        }
                    },
                    label = { Text(text = screen.name) }
                )


            }
        }


    }
}