![](/img/trans.png)
[英]Jetpack Compose Navigation - pass argument to startDestination
[英]Jetpack Compose Navigation: Direct navigation to route in a nested graph which is not startDestination
我正在开发 Jetpack Compose Navigation 演示,并且我有一个嵌套导航图,其中包含两个不同的嵌套路由和每个嵌套路由的屏幕:
Login Graph 有 3 条路线,用于显示三个不同的屏幕
主图有两条路线用于这些屏幕
嵌套图创建在MainActivity.kt中调用
setContent {
NavigationDemoTheme {
val navController = rememberNavController()
SetupNavGraph(navController = navController)
}
}
文件NestedNavGraph.kt中的 function 如下所示:
fun SetupNavGraph(navController: NavHostController) {
NavHost(navController = navController, startDestination = "login_route")
{
loginGraph(navController = navController)
mainGraph(navController = navController)
}
}
在LoginNavGraph.kt文件中,我定义了路线和起始目的地
fun NavGraphBuilder.loginGraph(navController: NavController) {
navigation(startDestination = "login", route = "login_route") {
composable(route = "login") {
LoginScreen(navController = navController)
}
composable(route = "register") {
RegisterScreen(navController = navController)
}
composable(route = "recover") {
RecoverPasswordScreen(navController = navController)
}
}
}
在MainNavGraph.kt文件中,我定义了这两条路线和这个起始目的地:
navigation(startDestination = "home", route = "main_route") {
composable(route = "home") {
HomeScreen(navController = navController)
}
composable(route = "settings") {
SettingsScreen(navController = navController)
}
}
我现在的问题是:如何从 SettingsScreen 显示 RecoverPasswordScreen。 我知道我可以从 SettingsScreen 导航到“login_route”,但随后将显示 startDestination,即 LoginScreen。
// shows the LoginScreen because the startDestination in the "login_route" is set to "login"
navController.navigate(route = "login_route")
那么,如何直接导航到嵌套图形路由“login_route”中的路由“recover”? 我想到了以下“解决方法”:
将参数传递给“login_route”,例如:
navController.navigate(route = "login_route?destination=recover")
然后,我将只有一条路线作为目的地,例如“LoginView”。 这将像这样更改 loginGraph:
fun NavGraphBuilder.loginGraph(navController: NavController) {
navigation(startDestination = "login_view, route = "login_route/{destination}) {
composable(
route = "login_view",
arguments = listOf(
navArgument("destination") { defaultValue = "login" },
)
) { backStackEntry ->
val destination = backStackEntry.arguments?.getString("destination");
destination?.let { destination ->
LoginView(destination = destination)
}
}
}
}
LoginView 是可组合的,它将有一个自己的 NavHost,我可以在其中使用上一条路由中的查询参数设置 startDestination:
fun LoginView( destination : String = "login"){
val navController = rememberNavController()
var startDestination = destination;
Scaffold ()
{
NavHost(
navController = navController,
startDestination = startDestination
) {
composable(route = "login") {
LoginScreen(navController = navController)
}
composable(route = "register") {
RegisterScreen(navController = navController)
}
composable(route = "recover") {
RecoverPasswordScreen(navController = navController)
}
}
}
现在我应该可以从 SettingsScreen 调用 RecoverPasswordScreen 了:
navController.navigate(route = "login_route?destination=recover")
另一种可能性是在 MainGraph 中为 RecoverPassword Screen 定义额外的路径。 是否有任何其他可能直接访问嵌套图中的路线? 如果可以在路由到“login_route”时动态更改 startDestination,那就太好了,但我不知道这如何或是否可能。
Compose 允许您(使用参数导航) 。 这使您可以导航到您所谓的“嵌套路由”,即屏幕中的特定部分。
现在,这是一个简单的解释,我可以离开你,让你弄清楚。 但是我认为这对您没有帮助,因为我认为您已经以一种困难的方式实现了导航。 因此,为什么尝试导航有点复杂。
这是一种更好的实现方式,以便像您想要的那样导航(从设置屏幕恢复密码屏幕)更容易。
将任何称为Main的内容更改为您的 AppName。
我还没有添加你所有的屏幕
//you could pass in parameters if needed into this constructor
enum class MainScreen(){
//these are your screens
LogIn(),
Settings(),
Recover(),
Home();
companion object {
fun fromRoute(route: String?): MainScreen =
when (route?.substringBefore("/")) {
LogIn.name -> LogIn
Home.name -> Home
Settings.name -> Settings
Recover.name -> Recover
//add the remaining screens
// a null route resolves to LogInScreen.
null -> LogIn
else -> throw IllegalArgumentException("Route $route is not recognized.")
}
}
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MainApp()
}
}
}
@Composable
fun MainApp() {
MainTheme {
val allScreens = MainScreen.values().toList()
val navController = rememberNavController()
val backStackEntry = navController.currentBackStackEntryAsState()
// currentScrren user is on good if app is large
val currentScreen = MainScreen.fromRoute(
backStackEntry.value?.destination?.route
)
//Using scaffold is a good idea
Scaffold(
//add topAppBar and all other things here
) { innerPadding ->
MainNavHost(navController = navController, modifier = Modifier.padding(innerPadding))
}
}
}
//Scaffold requires innerPadding so remove if you decide not to use scaffold
@Composable
fun MainNavHost(navController: NavHostController, modifier: Modifier = Modifier) {
NavHost(
navController = navController,
startDestination = LogIn.name,
modifier = modifier
) {
composable(LogIn.name) {
/**
Your body for logIn page
**/
}
//this is how you will navigate to Recover Screen from settings
composable(Settings.name) {
SettingsBody(onClickRecoverScreen = {navController.navigate(Recover.name)})
}
}
composable(Recover.name) {
/**
Your body for Recover page
**/
}
composable(Home.name) {
/**
Your body for Home page
**/
}
}
@Composable
fun SettingsBody(
//this callback is how you will navigate from Settings to RecoverPassword
onClickRecoverScreen: () -> Unit = {},
) {
Column(
//Add your designs for this screen
) {
Button(onClick = {onClickRecoverScreen})
}
}
这是实现导航的最简单的方法(在我看来),因为您可以简单地添加回调以导航到应用程序中的不同位置,并且它更具可测试性(如果您测试;))和可扩展性。 您还可以添加深层链接并使用 arguments(如上所述)导航到应用程序的特定部分(例如,帐户屏幕中的特定帐户)
如果你想了解更多,我强烈推荐这个Navigation Codelab 。
一种可能的解决方案是使用导航图中定义的深度链接——它们也适用于嵌套目的地。 然后,您可以使用navController.navigate(deepLinkUri)
而不是导航到路由名称
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.