簡體   English   中英

Jetpack Compose Navigation - 將參數傳遞給 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 >)

所有功勞歸功於ianhanniballakePeter 在我的例子中,我沒有在參數數據的路由中添加任何額外的(強制鍵/可選鍵)。 我保持路線清潔,如下所示:

導航圖:

 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM