![](/img/trans.png)
[英]Jetpack Compose Navigation: Direct navigation to route in a nested graph which is not startDestination
[英]Jetpack Compose Navigation - pass argument to startDestination
我正在构建的应用程序使用带路线的组合导航。 挑战在于起始目的地是动态的。
这是一个最小的例子:
class MainActivity : ComponentActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "dynamic/1", // doesn't work
// startDestination = "static", // workaround
) {
composable(
route = "dynamic/{$ARG_ID}",
arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType }),
) {
val id = it.arguments?.getString(ARG_ID)
Text("dynamic route, received argument: $id!")
}
// part of the workaround
// composable(
// route = "static",
// ) {
// LaunchedEffect(this) {
// navController.navigate("dynamic/1")
// }
// }
}
}
}
companion object
{
const val ARG_ID = "id"
}
}
该应用程序崩溃
java.lang.IllegalArgumentException: navigation destination route/1 is not a direct child of this NavGraph
该问题仅在“动态”路线用作起始目的地时才存在。 这可以通过使用startDestination = "static"
来验证。
虽然,“静态”路由解决方法有效,但我正在寻找没有它的解决方案,因为它有点混淆了代码,并且还在后台堆栈中创建了一个额外的条目。
-> 重现问题的完整代码示例
相关问题
编辑:
我想强调的是,原始示例过去不包含“静态”可组合项。 我只添加了“静态”可组合项以获得有效的startDestination
并证明可以导航到“动态”可组合项。
更新:
即使切换到可选 arguments 的查询参数语法,提供默认值,并设置没有任何参数的起始目的地也不起作用。
以下变化
NavHost(
navController = navController,
startDestination = "dynamic",
) {
composable(
route = "dynamic?$ARG_ID={$ARG_ID}",
arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType; defaultValue = "1" }),
) {
val id = it.arguments?.getString(ARG_ID)
Text("dynamic route, received argument: $id!")
}
}
导致异常
java.lang.IllegalArgumentException: navigation destination dynamic is not a direct child of this NavGraph
完全归功于ianhanniballake ,他在评论中向我解释了解决方案。 我将在这里展示我的代码示例的工作版本。
对我来说最大的见解是:
startDestination
不能匹配模式匹配意义上的可组合route
,但它必须是完全相同的字符串。
这意味着参数不能直接通过startDestination
设置,而必须通过参数的defaultValue
设置。
这是工作示例:
class MainActivity : ComponentActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
NavHost(
navController = navController,
// 1st change: Set startDestination to the exact string of route
startDestination = "dynamic/{$ARG_ID}", // NOT "dynamic/1", provide arguments via defaultValue
) {
composable(
route = "dynamic/{$ARG_ID}",
// 2nd change: Set startDestination argument via defaultValue
arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType; defaultValue = "1" }),
) {
val id = it.arguments?.getString(ARG_ID)
Text("dynamic route, received argument: $id!")
}
}
}
}
companion object
{
const val ARG_ID = "id"
}
}
该方法同样适用于以查询参数形式提供的参数。
老实说,我认为这是一个小限制,因为现在开始路线决定了defaultValue
必须是什么。 我可能想设置一个不同的defaultValue
或根本没有。 然而,在大多数情况下,这应该是最优雅的解决方案。
不应在“startDestination”NavHost 中使用动态路由值 --> navController.navigate(<dynamic route >)
所有功劳归功于ianhanniballake和Peter 。 在我的例子中,我没有在参数数据的路由中添加任何额外的(强制键/可选键)。 我保持路线清洁,如下所示:
导航图:
navigation(route = Route.Root.route, startDestination = Route.SubmitForm.route) {
composable(
route = Route.SubmitForm.route,
arguments = listOf(
navArgument(ARG_KEY) {
type = NavType.StringType
defaultValue = JsonConverter.toJson(user, User::class.java)
},
)
)
}
路由封class:
sealed class Route(val route: String) {
object MyRoute : Route("$ROOT/submit-form")
}
在视图 model 中,只需获取如下数据:
@HiltViewModel
class MyViewModel @Inject constructor(
stateHandle: SavedStateHandle,
) : ViewModel {
lateinit var user
init {
user = stateHandle.get<String>(ARG_NAME) // Supported data types
}
}
它对我有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.