Получить текущий экран в навигационной безопасности Jetpack Compose

Экраны

@Serializable
sealed class Screen {
    @Serializable
    data object Home : Screen()

    @Serializable
    data class Profile(val name: String) : Screen()
}

Настроить навигацию

@Composable
fun AppNavigation(
    modifier: Modifier = Modifier,
    startDestination: Screen = Screen.Home,
    navController: NavHostController = rememberNavController()
) {
    val currentNavBackStackEntry: NavBackStackEntry? by navController.currentBackStackEntryAsState()

    // Error
    val currentScreen: Screen = currentNavBackStackEntry?.toRoute<Screen>() ?: Screen.Home

    val navGraph = navController.createGraph(
        startDestination = startDestination,
    ) {
        composable<Screen.Home> {
            HomeScreen(onNavigateToProfile = { navController.navigate(it) })
        }
        composable<Screen.Profile> { navBackStackEntry ->
            val profile = navBackStackEntry.toRoute<Screen.Profile>()
            ProfileScreen(name = profile.name)
        }
    }

    NavHost(navController = navController, graph = navGraph, modifier = modifier)
}

Я пытаюсь получить текущий экран из набора реактивного ранца навигационного типа. Но toRoute() используйте только с маршрутами в навигационном графе.

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

shotmeinthehead 02.07.2024 12:16

Пожалуйста, укажите, что вы планируете делать currentScreen — вы пытаетесь сравнить это с чем-то другим?

ianhanniballake 02.07.2024 16:06

@ianhanniballake Мое временное решение — сравнить строки currentNavBackStackEntry?.destination?.route и Screen::class.qualifiedName. Есть ли другой способ получить текущий экран типа Screen

Thai Manh 03.07.2024 03:54

Вы фактически не ответили на мой вопрос - где вы на самом деле используете текущий экран? Ваш код по-прежнему ничего не делает с этой информацией. Пожалуйста, включите этот код.

ianhanniballake 03.07.2024 04:30

вам нужен вариант использования currentScreen? хм, заголовок TopAppBar, условная навигация...

Thai Manh 03.07.2024 05:45

«Вам нужен вариант использования для currentScreen? хм, заголовок TopAppBar, условие навигации...» — вы знаете «текущий экран» внутри вашего навигационного графа. Например, внутри лямбды composable<Screen.Home> вы знаете, что «текущий экран» — это Screen.Home. Там вы можете обновлять состояние по мере необходимости, чтобы влиять на изменения в элементах за пределами навигационного графика, например в некоторых заголовках в строке заголовка. Я подозреваю, что именно поэтому Ян просит вас показать код, который будет зависеть от currentScreen — такое ощущение, что есть и другие решения.

CommonsWare 05.07.2024 14:36
0
6
121
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Функция hasRoute() может помочь вам с текущим экраном следующим образом:

val navBackStackEntry by navController.currentBackStackEntryAsState()

navBackStackEntry?.destination?.let { currentDestination ->
    shouldShowAppBar = !currentDestination.hasRoute(Settings::class)
}

Не красиво, но пока работает.

@Serializable
sealed class Screen(@StringRes val title: Int, val showAppBar: Boolean = true) {
    @Serializable
    data object Home : Screen(R.string.app_name)
    @Serializable
    data object Login : Screen(R.string.app_name, showAppBar = false)
}

val backStackEntry by navController.currentBackStackEntryAsState()
val currentScreen = backStackEntry?.destination?.let {
    when (it.route) {
        Screen.Login::class.qualifiedName -> Screen.Login
        else -> Screen.Home
    }
} ?: Screen.Home

Scaffold(
   topBar = {
        if (currentScreen.showAppBar) {
            AppBar()
        }
   },
)

Другие вопросы по теме