![](/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.