Вручную предварительно заполнить бэкстек навигации в Android / Jetpack Compose

#android #android-jetpack-compose #android-navigation #jetpack-compose-navigation

#Android #android-jetpack-compose #android-навигация #jetpack-compose-навигация

Вопрос:

Возможно ли предварительно заполнить бэкстек навигации в Android / Jetpack Compose?

У меня есть глубокая ссылка, которая переходит вглубь иерархии навигации, однако при обратном нажатии она переходит к корневому маршруту.

Пример:

Маршрут.Главная -> Маршрут.Список -> Маршрут.Подробности (аргумент: id)

Глубокая ссылка: https://mywebsite.com/details/id

Текущее поведение: он открывает маршрут.Подробности с правильным аргументом, однако, onBack открывает маршрут.Главная

Желаемое поведение: он должен открыть маршрут.Список

Я знаю, что могу вручную «запрограммировать» это поведение, но я бы предпочел «настроить» его.

Комментарии:

1. Это одна из причин, по которой я отказался от использования навигационного API Compose и разработал свой собственный, который поддерживает глубокие ссылки, передает объекты на экраны и решает поднятую вами проблему. Вы можете попробовать. Демонстрация включает в себя глубокую ссылку, которая должным образом управляет возвратом к предыдущим экранам: github.com/JohannBlake/Jetmagic

Ответ №1:

У меня была похожая проблема раньше, и, похоже, это ожидаемое поведение библиотеки. Я имею в виду, что если пользователь откроет приложение из глубокой ссылки, которая отображает Screen_C, а затем нажмет назад, должен отображаться главный экран приложения. Так что, возможно, вам нужно пересмотреть удобство использования приложения.

Однако, если даже вы хотите сделать обходной путь, вручную обработав нажатие назад. Используя приведенную ниже функцию

 fun navigatingBack(
    navController: NavHostController,
    destinationRoute: String
) {
    val hasBackstackTheDestinationRoute = navController.backQueue.find {
        it.destination.route == destinationRoute
    } != null
    // if the destination is already in the backstack, simply go back
    if (hasBackstackTheDestinationRoute) {
        navController.popBackStack()
    } else {
        // otherwise, navigate to a new destination popping the current destination
        navController.navigate(destinationRoute) {
            navController.currentBackStackEntry?.destination?.route?.let {
                popUpTo(it) {
                    inclusive = true
                }
            }
        }
    }
}
 

Допустим, вы объявляете экраны ScreenA , ScreenB и ScreenC .

 composable("__A__") {
    ScreenA(navController)
}
composable("__B__") {
    ScreenB(navController)
}
composable("__C__") {
    ScreenC(navController)
}
 

Вы можете сделать следующее:

 @Composable
fun ScreenA(navController: NavHostController) {
    Button(onClick = {
        navController.navigate("__B__")
    }) {
        Text(text = "Screen A - Go to B")
    }
}

@Composable
fun ScreenB(navController: NavHostController) {
    Button(onClick = {
        navController.navigate("__C__")
    }) {
        Text(text = "Screen B - Go to C")
    }
    BackHandler {
        navigatingBack(navController, "__A__")
    }
}

@Composable
fun ScreenC(navController: NavHostController) {
    Text(text = "Screen C")
    BackHandler {
        navigatingBack(navController, "__B__")
    }
}
 

Используя приведенный выше пример, если вы перейдете непосредственно к ScreenC и нажмете назад, ScreenB отобразится. Аналогичное происходит в ScreenB , где ScreenA отображается при нажатии кнопки «Назад».