Search code examples
androidkotlinandroid-jetpack-composeandroid-navigation

Jetpack Compose: navigate to X screen (jump) keeping back-stack history


Have an Activity which holds NavHostController, when activity starts, need to navigate X screen, but pressing back need to navigate to previous screen, not to the start destination (because navigating to X was from startDest).

@OptIn(ExperimentalMaterialNavigationApi::class)
@Composable
private fun NavHostController(
    navController: NavHostController,
    startDest: String = "screen 1"
) {
    NavHost(
        navController = navController,
        startDestination = startDest,
    ) {
        composable("screen 1") {}
        composable("screen 2") {}
        ...
        composable("screen N") {}
}}

EXAMPLE:

have screens like: "screen 1-2-3-4-5..N"

and the "screen 1" is start destination, activity starts and nav-ctrl jumps to screen 5(for example), and the back press need to work like: to 4, 3, 2.. NOT direct 1 (as start destination is 1)

Question: How to set back stack history in nav controller OR How navigate (jump) with keeping back stack order.


Solution

  • OK actually solved this issue using view-pager see here

    So It can jump easily any screen on View-pager as current page,

    LaunchedEffect(
            key1 = currentPage,
            block = {
                pagerState.animateScrollToPage(currentPage)
            })
    

    and overrides back button and action to go back through view-pager pages (currentPage-1) if current page. is 0, then closes whole screen (activity).

    Also disabled user events on view-pager to not allow change page with swiping, set userScrollEnabled to false.

    userScrollEnabled: Boolean = false
    

    BUT Second solution using navigation.

        private const val STEPS: String = "steps"
        private const val CURRENT_STEP: String = "currentStep"
        private const val PATH: String = "your_screen/{$STEPS}/{$CURRENT_STEP}"
    
        @Composable
        fun MyComposable() {
            val navController = rememberNavController()
            NavHost(
                navController = navController,
                startDestination = PATH,
                modifier = modifier.fillMaxSize(),
            ) {
                composable(
                    route = PATH,
                    arguments = listOf(
                        navArgument(CURRENT_STEP) {
                            type = NavType.IntType
                            defaultValue = 0
                        },
                    )
                ) { backStackEntry ->
                    PagesScreen(
                        navController = navController,
                        currentStep = backStackEntry.arguments?.getInt(CURRENT_STEP) ?: 0,
                    )
                }
            }    
        }
    
    @Composable
    private fun PagesScreen(
        navController: NavController,
        modifier: Modifier = Modifier,
        currentStep: Int = 0,
        onFinish: () -> Unit = {},
    ) {
        val stepsCount = 6 // your navigation steps pages count
       // show current page
    
        val goToNextScreen = {
            if (currentStep < stepsCount - 1) {
                navController.navigate("your_screen/$stepsCount/${currentStep + 1}")
            } else {
              onFinish()
            }
        }
        val goToPreviousScreen = {
            if (currentStep > 0) {
                navController.navigate("your_screen/$stepsCount/${currentStep - 1}")
            } else {
              onFinish()
            }
        }
    }