Noa*_*oah 13 android kotlin android-jetpack-navigation android-jetpack-compose
我想BluetoothDevice使用组合导航将 Parcelable 对象 ( ) 传递给可组合对象。
传递原始类型很容易:
composable(
"profile/{userId}",
arguments = listOf(navArgument("userId") { type = NavType.StringType })
) {...}
Run Code Online (Sandbox Code Playgroud)
navController.navigate("profile/user1234")
Run Code Online (Sandbox Code Playgroud)
但是我不能在路由中传递一个parcelable 对象,除非我可以将它序列化为一个字符串。
composable(
"deviceDetails/{device}",
arguments = listOf(navArgument("device") { type = NavType.ParcelableType(BluetoothDevice::class.java) })
) {...}
Run Code Online (Sandbox Code Playgroud)
val device: BluetoothDevice = ...
navController.navigate("deviceDetails/$device")
Run Code Online (Sandbox Code Playgroud)
上面的代码显然不起作用,因为它只是隐式调用toString().
有没有办法要么序列化Parcelable的String,所以我可以通过它的路线或通过导航参数作为比其他函数的对象navigate(route: String)?
Val*_*yev 36
我为 NavController 编写了一个小扩展。
import android.os.Bundle
import androidx.core.net.toUri
import androidx.navigation.*
fun NavController.navigate(
route: String,
args: Bundle,
navOptions: NavOptions? = null,
navigatorExtras: Navigator.Extras? = null
) {
val routeLink = NavDeepLinkRequest
.Builder
.fromUri(NavDestination.createRoute(route).toUri())
.build()
val deepLinkMatch = graph.matchDeepLink(routeLink)
if (deepLinkMatch != null) {
val destination = deepLinkMatch.destination
val id = destination.id
navigate(id, args, navOptions, navigatorExtras)
} else {
navigate(route, navOptions, navigatorExtras)
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,至少有 16 个带有不同参数的函数“ navigate ”,所以它只是一个可供使用的转换器
public open fun navigate(@IdRes resId: Int, args: Bundle?)
Run Code Online (Sandbox Code Playgroud)
因此,使用此扩展,您可以使用 Compose Navigation,而无需这些可怕的深度链接参数作为路由参数。
ngl*_*ber 15
编辑:更新为beta-07
基本上你可以做到以下几点:
// In the source screen...
navController.currentBackStackEntry?.arguments =
Bundle().apply {
putParcelable("bt_device", device)
}
navController.navigate("deviceDetails")
Run Code Online (Sandbox Code Playgroud)
在详细信息屏幕中...
val device = navController.previousBackStackEntry
?.arguments?.getParcelable<BluetoothDevice>("bt_device")
Run Code Online (Sandbox Code Playgroud)
这是我使用的版本BackStackEntry
用法:
composable("your_route") { entry ->
AwesomeScreen(entry.requiredArg("your_arg_key"))
}
navController.navigate("your_route", "your_arg_key" to yourArg)
Run Code Online (Sandbox Code Playgroud)
扩展:
fun NavController.navigate(route: String, vararg args: Pair<String, Parcelable>) {
navigate(route)
requireNotNull(currentBackStackEntry?.arguments).apply {
args.forEach { (key: String, arg: Parcelable) ->
putParcelable(key, arg)
}
}
}
inline fun <reified T : Parcelable> NavBackStackEntry.requiredArg(key: String): T {
return requireNotNull(arguments) { "arguments bundle is null" }.run {
requireNotNull(getParcelable(key)) { "argument for $key is null" }
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
args: Bundle?参数val destination = navController.graph.findNode("YOUR_ROUTE")
if (destination != null) {
navController.navigate(
destination.id,
bundleOf("key" to value)
)
}
Run Code Online (Sandbox Code Playgroud)
我想出了这个解决方案:
fun NavController.navigate(
route: String,
args: Bundle,
navOptions: NavOptions? = null,
navigatorExtras: Navigator.Extras? = null
) {
val nodeId = graph.findNode(route = route)?.id
if (nodeId != null) {
navigate(nodeId, args, navOptions, navigatorExtras)
}
}
Run Code Online (Sandbox Code Playgroud)
这通过导航图中的ID来识别注册的路线,完全绕过了深层链接机制并回退到原始方法。
在 NavGraphBuilder 中注册您的路线,如下所示:
composable(
route = "MyRoute",
) {
MyScreen(
navController = navController,
myArgument = it.arguments?.getParcelable("myParcelableArg")
)
}
Run Code Online (Sandbox Code Playgroud)
并像这样导航:
navController.navigate(
route = "MyRoute",
args = bundleOf(
"myParcelableArg" to MyParcelable()
)
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2672 次 |
| 最近记录: |