Zaprojektuj wykres nawigacyjny

Komponent Nawigacja używa grafu nawigacji do zarządzania nawigacją w aplikacji. Graf nawigacji to struktura danych zawierająca wszystkie miejsca docelowe w aplikacji i połączenia między nimi.

Typy miejsc docelowych

Istnieją 3 ogólne typy miejsc docelowych: hostowane, dialogowe i z aktywizacją. W tabeli poniżej przedstawiono te 3 typy miejsc docelowych i ich przeznaczenie.

Typ

Opis

Przykłady zastosowań

Hostowane

Wypełnia cały element nawigacji. Oznacza to, że rozmiar hostowanego miejsca docelowego jest taki sam jak rozmiar hosta nawigacji, a poprzednie miejsca docelowe są niewidoczne.

Ekrany główne i szczegółowe.

Dialog

Zawiera komponenty UI nakładki. To UI nie jest powiązane z lokalizacją hosta nawigacji ani jego rozmiarem. Poprzednie miejsca docelowe są widoczne pod aktualnym miejscem docelowym.

alerty, wybory, formularze.

Aktywność

Reprezentują unikalne ekrany lub funkcje w aplikacji.

służyć jako punkt wyjścia do grafu nawigacji, który uruchamia nową aktywność Androida zarządzaną oddzielnie od komponentu nawigacji;

W ramach nowoczesnego procesu tworzenia aplikacji na Androida aplikacja składa się z jednego działania. Dlatego miejsca docelowe aktywności najlepiej sprawdzają się podczas interakcji z aktywnościami innych firm lub w ramach procesu migracji.

Ten dokument zawiera przykłady hostowanych miejsc docelowych, które są najczęstszymi i podstawowymi miejscami docelowymi. Informacje o innych usługach docelowych znajdziesz w tych przewodnikach:

Platformy

Chociaż w każdym przypadku stosuje się ten sam ogólny proces, sposób tworzenia hosta nawigacji i grafu zależy od używanej platformy interfejsu.

  • Komponowanie: użyj modułu NavHost. Dodaj do niego NavGraph za pomocą Kotlin DSL. Możesz utworzyć wykres na 2 sposoby:
    • W ramach NavHost: zbuduj graf nawigacji bezpośrednio w ramach dodawania NavHost.
    • Automatycznie: użyj metody NavController.createGraph(), aby utworzyć obiekt NavGraph i przekazać go bezpośrednio do obiektu NavHost.
  • Fragmenty: jeśli fragmenty są używane z ramką interfejsu użytkownika widoków, jako hosta użyj widoku NavHostFragment. Graf w usłudze Google Analytics można utworzyć na kilka sposobów:
    • Programowo: użyj Kotlin DSL, aby utworzyć NavGraph i bezpośrednio zastosować go do NavHostFragment.
      • Funkcja createGraph() używana w Kotlin DSL w przypadku fragmentów i Compose jest taka sama.
    • XML: zapisz hosta nawigacji i wykres bezpośrednio w formacie XML.
    • Edytor Android Studio: użyj edytora GUI w Android Studio, aby utworzyć i dostosować wykres jako plik zasobu XML.

Compose

W komponencie Compose użyj obiektu lub klasy serializowanej, aby zdefiniować trasę. Trasa opisuje, jak dotrzeć do miejsca docelowego, i zawiera wszystkie informacje wymagane przez to miejsce.

Użyj adnotacji @Serializable, aby automatycznie utworzyć niezbędne metody serializacji i deserializacji dla typów tras. Ta adnotacja jest dostarczana przez wtyczkę Kotlin Serialization. Aby dodać tę wtyczkę, wykonaj te instrukcje.

Po zdefiniowaniu tras użyj komponentu NavHost, aby utworzyć graf nawigacji. Rozważ ten przykład:

@Serializable
object Profile
@Serializable
object FriendsList

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
    // Add more destinations similarly.
}
  1. Obiekt serializowany reprezentuje obie trasy: ProfileFriendsList.
  2. Wywołanie komponentu NavHost przekazuje NavController oraz trasę do miejsca docelowego.
  3. Funkcja lambda przekazana do NavHost wywołuje w końcu funkcję NavController.createGraph() i zwraca wartość NavGraph.
  4. Każda ścieżka jest podawana jako argument typu do NavGraphBuilder.composable<T>(), który dodaje miejsce docelowe do otrzymanego NavGraph.
  5. Funkcja lambda przekazana do composable to to, co NavHost wyświetla dla tego miejsca docelowego.

Lambda

Aby lepiej zrozumieć funkcję lambda, która tworzy zmienną NavGraph, pamiętaj, że aby utworzyć ten sam wykres co w poprzednim fragmencie kodu, możesz utworzyć zmienną NavGraph osobno za pomocą funkcji NavController.createGraph() i przekazać ją bezpośrednio do funkcji NavHost:

val navGraph by remember(navController) {
  navController.createGraph(startDestination = Profile)) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
  }
}
NavHost(navController, navGraph)

Przekazywanie argumentów

Jeśli chcesz przekazać dane do miejsca docelowego, zdefiniuj trasę za pomocą klasy z parametrami. Na przykład trasa Profile to klasa danych z parametrem name.

@Serializable
data class Profile(val name: String)

Za każdym razem, gdy chcesz przekazać argumenty do tego miejsca docelowego, tworzysz instancję klasy trasy, przekazując argumenty do konstruktora klasy.

W przypadku argumentów opcjonalnych twórz pola z możliwością wartości null i wartością domyślną.

@Serializable
data class Profile(val nickname: String? = null)

Pobieranie instancji trasy

Możesz uzyskać instancję trasy za pomocą NavBackStackEntry.toRoute() lub SavedStateHandle.toRoute(). Gdy tworzysz miejsce docelowe za pomocą parametru composable(), parametr NavBackStackEntry jest dostępny jako parametr.

@Serializable
data class Profile(val name: String)

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile(name="John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(name = profile.name) }
}

Zwróć uwagę na te informacje w tym fragmencie kodu:

  • Trasa Profile określa punkt początkowy w grafu nawigacji, a argument "John Smith" w funkcji name to "John Smith".
  • Miejsce docelowe to blok composable<Profile>{}.
  • Składnik ProfileScreen przyjmuje wartość profile.name jako argument name.
  • W związku z tym wartość "John Smith" jest przekazywana do ProfileScreen.

Minimalny przykład

Pełny przykład działania funkcji NavController i NavHost:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Define the ProfileScreen composable.
@Composable
fun ProfileScreen(
    profile: Profile
    onNavigateToFriendsList: () -> Unit,
  ) {
  Text("Profile for ${profile.name}")
  Button(onClick = { onNavigateToFriendsList() }) {
    Text("Go to Friends List")
  }
}

// Define the FriendsListScreen composable.
@Composable
fun FriendsListScreen(onNavigateToProfile: () -> Unit) {
  Text("Friends List")
  Button(onClick = { onNavigateToProfile() }) {
    Text("Go to Profile")
  }
}

// Define the MyApp composable, including the `NavController` and `NavHost`.
@Composable
fun MyApp() {
  val navController = rememberNavController()
  NavHost(navController, startDestination = Profile(name = "John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(
            profile = profile,
            onNavigateToFriendsList = {
                navController.navigate(route = FriendsList)
            }
        )
    }
    composable<FriendsList> {
      FriendsListScreen(
        onNavigateToProfile = {
          navController.navigate(
            route = Profile(name = "Aisha Devi")
          )
        }
      )
    }
  }
}

Jak widać w tym fragmencie kodu, zamiast przekazywać parametr NavController do komponentów, możesz ujawnić zdarzenie dla parametru NavHost. Oznacza to, że twoje komponenty powinny mieć parametr typu () -> Unit, do którego NavHost przekazuje funkcję lambda, która wywołuje funkcję NavController.navigate().

Fragmenty

Jak opisano w poprzednich sekcjach, podczas korzystania z fragmentów możesz utworzyć graficzną mapę nawigacji za pomocą Kotlin DSL, XML lub edytora Android Studio.

W następnych sekcjach omawiamy te różne podejścia.

Automatycznie

Kotlin DSL zapewnia programowy sposób tworzenia grafu nawigacyjnego za pomocą fragmentów. W wielu aspektach jest to rozwiązanie bardziej przejrzyste i nowocześniejsze niż używanie pliku zasobów XML.

Rozważ przykład poniżej, który implementuje wykres nawigacji na 2 ekranach.

Najpierw musisz utworzyć element NavHostFragment, który nie może zawierać element app:navGraph:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

Następnie przekaż idNavHostFragment do NavController.findNavController. W ten sposób kontroler nawigacji zostaje powiązany z elementem NavHostFragment.

Następnie wywołanie funkcji NavController.createGraph() łączy wykres z funkcją NavController, a co za tym idzie, także z funkcją NavHostFragment:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Retrieve the NavController.
val navController = findNavController(R.id.nav_host_fragment)

// Add the graph to the NavController with `createGraph()`.
navController.graph = navController.createGraph(
    startDestination = Profile(name = "John Smith")
) {
    // Associate each destination with one of the route constants.
    fragment<ProfileFragment, Profile> {
        label = "Profile"
    }

    fragment<FriendsListFragment, FriendsList>() {
        label = "Friends List"
    }

    // Add other fragment destinations similarly.
}

Używanie DSL w ten sposób jest bardzo podobne do procesu opisanego w poprzedniej sekcji dotyczącej tworzenia. Na przykład w obu przypadkach funkcja NavController.createGraph() generuje wartość NavGraph. Podobnie jak NavGraphBuilder.composable() dodaje do grafu miejsca docelowe, które można łączyć, tak NavGraphBuilder.fragment() dodaje fragment miejsca docelowego.

Więcej informacji o korzystaniu z języka DSL w Kotlinie znajdziesz w artykule Tworzenie grafu za pomocą DSL w klasie NavGraphBuilder.

XML

Możesz samodzielnie napisać kod XML. Poniższy przykład jest lustrzanym odpowiednikiem przykładu z 2 ekranami z poprzedniej sekcji.

Najpierw utwórz NavHostFragment. Jest to host nawigacji, który zawiera rzeczywisty graf nawigacji.

Minimalna implementacja NavHostFragment:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navGraph="@navigation/nav_graph" />

</FrameLayout>

Element NavHostFragment zawiera atrybut app:navGraph. Użyj tego atrybutu, aby połączyć graf nawigacji z hostem nawigacji. Poniżej znajdziesz przykład implementacji wykresu:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/profile">

    <fragment
        android:id="@+id/profile"
        android:name="com.example.ProfileFragment"
        android:label="Profile">

        <!-- Action to navigate from Profile to Friends List. -->
        <action
            android:id="@+id/action_profile_to_friendslist"
            app:destination="@id/friendslist" />
    </fragment>

    <fragment
        android:id="@+id/friendslist"
        android:name="com.example.FriendsListFragment"
        android:label="Friends List" />

    <!-- Add other fragment destinations similarly. -->
</navigation>

Za pomocą działań określasz połączenia między różnymi miejscami docelowymi. W tym przykładzie fragment profile zawiera działanie, które przekierowuje do fragmentu friendslist. Więcej informacji znajdziesz w artykule Używanie działań i fragmentów nawigacji.

.

Edytor

Grafikiem nawigacji aplikacji możesz zarządzać za pomocą Edytora nawigacji w Android Studio. Jest to interfejs graficzny, którego możesz używać do tworzenia i edytowania pliku XML NavigationFragment, jak pokazano w poprzedniej sekcji.

Więcej informacji znajdziesz w Edytorze nawigacji.

Wykresy zagnieżdżone

Możesz też używać wykresów zagnieżdżonych. Polega to na użyciu grafu jako celu nawigacji. Więcej informacji znajdziesz w artykule Wyrażenia z wykresami zagnieżdżonymi.

Więcej informacji

Więcej informacji o podstawowych pojęciach związanych z nawigacją znajdziesz w tych przewodnikach: