Параметры навигации

Последнее обновление: 17.04.2024

Иногда бывает необходимо при переходе от одного экрана к другому требуется передать аргумент в пункт назначения. 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")
}

В итоге при нажатии на кнопку произойдет следующая последовательность событий:

  1. Для текущего пункта назначения создается запись для стека

  2. Текущее значение someId сохраняется в эту запись

  3. Запись помещается в стек навигации

  4. Вызывается функция composable() в объявлении NavHost

  5. Концевая лямбда функции 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, который отобразит информацию по данному пользователю:

Навигация и передача параметров в приложении на Jetpack Compose на Kotlin в Android
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850