Иногда бывает необходимо при переходе от одного экрана к другому требуется передать аргумент в пункт назначения. Compose поддерживает передачу аргументов самых различных типов. Для этого сначала надо добавить именя аргумента к маршруту назначения:
NavHost(navController = navController, startDestination = Routes.Home.route) { composable(Routes.User.route + "/{userId}") { stackEntry -> val userId = stackEntry.arguments?.getString("userId") User(userId) } }
В данном случае в маршрут User передается аргумент "userId". Когда приложение запускает переход к месту назначения, значение аргумента сохраняется в соответствующей записи стека навигации. Запись стека передается
в качестве параметра в концевую лямбду функции composable()
, откуда ее можно извлечь и передать компоненту User.
По умолчанию предполагается, что аргумент навигации имеет тип String, соответственно для его извлечения из записи стека применяется метод getString()
. Чтобы передать аргументы разных типов, тип необходимо указать с помощью перечисления NavType
через параметр arguments функции composable()
. В следующем примере тип параметра объявлен как тип Int, соответственно для его извлечения используется метод getInt()
:
composable( Routes.User.route + "/{userId}", arguments = listOf(navArgument("userId") { type = NavType.IntType }) ){ navBackStack -> User(navBackStack.arguments?.getInt("userId")) }
На своей стороне компонент User должен ожидать получения аргумент userId через одноименный параметр:
@Composable fun User(userId: String?) { ......................... }
И на последнем шаге надо передать значение аргумента при вызове метода navigation()
, например, добавив значение аргумента в конец маршрута назначения:
val someId = 22 // некоторое значение, которое передается аргументу навигации Button(onClick = { navController.navigate(Routes.User.route + "/$someId") }) { Text(text = "Show User") }
В итоге при нажатии на кнопку произойдет следующая последовательность событий:
Для текущего пункта назначения создается запись для стека
Текущее значение someId сохраняется в эту запись
Запись помещается в стек навигации
Вызывается функция composable() в объявлении NavHost
Концевая лямбда функции composable() извлекает значение аргумента из записи стека и передает его в компонент User
Рассмотрим простейший пример применения параметров при навигации:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Main() } } } sealed class UserRoutes(val route: String) { object Users : UserRoutes("users") object User : UserRoutes("user") } @Composable fun Main() { val navController = rememberNavController() val employees = listOf( Employee(1, "Tom", 39), Employee(2, "Bob", 43), Employee(3, "Sam", 28) ) NavHost(navController, startDestination = UserRoutes.Users.route) { composable(UserRoutes.Users.route) { Users(employees, navController) } composable(UserRoutes.User.route + "/{userId}", arguments = listOf(navArgument("userId") { type = NavType.IntType })) { stackEntry -> val userId = stackEntry.arguments?.getInt("userId") User(userId, employees) } } } @Composable fun Users(data: List<Employee>, navController: NavController){ LazyColumn { items(data){ u-> Row(Modifier.fillMaxWidth()){ Text(u.name, Modifier.padding(8.dp).clickable { navController.navigate("user/${u.id}") }, fontSize = 28.sp) } } } } @Composable fun User(userId:Int?, data: List<Employee>){ val user = data.find { it.id==userId } if(user!=null) { Column { Text("Id: ${user.id}", Modifier.padding(8.dp), fontSize = 22.sp) Text("Name: ${user.name}", Modifier.padding(8.dp), fontSize = 22.sp) Text("Age: ${user.age}", Modifier.padding(8.dp), fontSize = 22.sp) } } else{ Text("User Not Found") } } data class Employee(val id:Int, val name:String, val age:Int)
Здесь для описания данных используется класс Employee с тремя свойствами, из которых свойство id - идентификатор, уникально идентифицирует пользователя.
Компонент User применяется для отображения одного объекта Employee. Через параметры он получает идентификатор пользователя и список пользователей:
@Composable fun User(userId:Int?, data: List<Employee>){ val user = data.find { it.id==userId } ..............................................
Получив идентификатор, компонент извлекает из переданного списка нужного пользователя и выводит его данные на экран.
Компонент Users отображает список пользователей
@Composable fun Users(data: List<Employee>, navController: NavController){ LazyColumn { items(data){ u-> Text( u.name, Modifier.padding(8.dp).clickable { navController.navigate("user/${u.id}") }, fontSize = 28.sp ) } } }
По нажатию на каждый элемент списка будет происходить переход к отображению соответствующего пользователя. И при переходе передается в качестве аргумента навигации идентификатор пользователя
В компоненте Main создаем список пользователей для отображения и разворачиваем NavHost для его отображения:
fun Main() { val navController = rememberNavController() val employees = listOf( Employee(1, "Tom", 39), Employee(2, "Bob", 43), Employee(3, "Sam", 28) ) NavHost(navController, startDestination = UserRoutes.Users.route) { composable(UserRoutes.Users.route) { Users(employees, navController) } composable(UserRoutes.User.route + "/{userId}", arguments = listOf(navArgument("userId") { type = NavType.IntType })) { stackEntry -> val userId = stackEntry.arguments?.getInt("userId") User(userId, employees) } } }
В данном случае параметр userId определяется как значение типа Int, и для его получения применяется метод getInt()
Таким образом, если мы запустим приложение, мы увидим список пользователей. При нажатии на одного из пользователей в списке произойдет переход к компоненту User, который отобразит информацию по данному пользователю: