Zaprojektuj wykres nawigacyjny

Komponent Nawigacja używa wykresu nawigacyjnego do zarządzania poruszaniem się po aplikacji. Wykres nawigacyjny to struktura danych, która obejmuje wszystkie miejsca docelowe w aplikacji oraz połączenia między nimi.

Typy miejsc docelowych

Istnieją 3 ogólne typy miejsc docelowych: hostowane, okna dialogowe i aktywność. W poniższej tabeli opisujemy 3 typy miejsc docelowych i ich zastosowania.

Typ

Opis

Przykłady zastosowań

Hostowane

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

Ekran główny i ekran szczegółów.

Dialog

Widoczne są komponenty interfejsu nakładki. Nie jest on powiązany z lokalizacją hosta nawigacji ani jego rozmiarem. Poprzednie miejsca docelowe są widoczne poniżej miejsca docelowego.

Alerty, wybory, formularze.

Aktywność

Reprezentuje unikalne ekrany lub funkcje aplikacji.

Pełni funkcję punktu wyjścia z wykresu nawigacyjnego, który rozpoczyna nową aktywność na Androidzie zarządzanym niezależnie od komponentu Nawigacja.

We współczesnych programach na Androida aplikacja składa się z jednego działania. Dlatego miejsc docelowych aktywności najlepiej jest używać podczas interakcji z działaniami zewnętrznymi lub w ramach procesu migracji.

Ten dokument zawiera przykłady hostowanych miejsc docelowych, które są najpopularniejsze i najbardziej podstawowe. W tych przewodnikach znajdziesz informacje o innych usługach docelowych:

Platformy

W każdym przypadku obowiązuje ten sam ogólny przepływ pracy, ale dokładny sposób tworzenia hosta nawigacji i wykresu zależy od używanej platformy interfejsu.

  • Utwórz: użyj funkcji kompozycyjnej NavHost. Dodaj do niego NavGraph za pomocą DLSL Kotlin. Wykres można utworzyć na 2 sposoby:
    • W ramach obiektu NavHost: utwórz wykres nawigacyjny bezpośrednio w ramach dodawania obiektu NavHost.
    • Automatycznie: użyj metody NavController.createGraph(), aby utworzyć NavGraph i przekazać go bezpośrednio do NavHost.
  • Fragmenty: jeśli używasz fragmentów w strukturze interfejsu widoków, hostem jest NavHostFragment. Wykres nawigacyjny można utworzyć na kilka sposobów:
    • Programowo: użyj DSL Kotlin, aby utworzyć NavGraph i zastosować go bezpośrednio do NavHostFragment.
      • Funkcja createGraph() używana z DSL Kotlin zarówno w przypadku fragmentów, jak i tworzenia wiadomości jest taka sama.
    • XML: wpisz host nawigacji i wykres bezpośrednio w pliku XML.
    • Edytor Android Studio: użyj edytora GUI w Android Studio, aby utworzyć i dostosować wykres jako plik zasobów XML.

Utwórz

W narzędziu Compose zdefiniuj trasę za pomocą zserializowanego obiektu lub klasy. Trasa określa, jak dotrzeć do celu, i zawiera wszystkie wymagane informacje. Po zdefiniowaniu tras użyj funkcji NavHost, aby utworzyć wykres nawigacyjny. Przyjrzyjmy się temu przykładowi:

@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. Zserializowany obiekt reprezentuje każdą z 2 tras – Profile i FriendsList.
  2. Wywołanie funkcji kompozycyjnej NavHost przekazuje NavController i trasę do miejsca docelowego początkowego.
  3. Funkcja lambda przekazana do funkcji NavHost ostatecznie wywołuje NavController.createGraph() i zwraca NavGraph.
  4. Każda trasa jest dostarczana jako argument typu w funkcji NavGraphBuilder.composable<T>(), który dodaje miejsce docelowe do wynikowego NavGraph.
  5. Wartość lambda przekazana do composable to wynik, który NavHost wyświetla w przypadku danego miejsca docelowego.

Omówienie funkcji lambda

Aby lepiej zrozumieć, do czego służy funkcja lambda, która tworzy obiekt NavGraph, pamiętaj, że aby utworzyć taki sam wykres jak w poprzednim fragmencie, możesz utworzyć tabelę NavGraph oddzielnie 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 musisz przekazać dane do miejsca docelowego, zdefiniuj trasę za pomocą klasy z parametrami. Na przykład trasa Profile jest klasą danych z parametrem name.

@Serializable
data class Profile(val name: String)

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

Uzyskiwanie instancji trasy

Instancję trasy można uzyskać za pomocą metody NavBackStackEntry.toRoute() lub SavedStateHandle.toRoute(). Gdy tworzysz miejsce docelowe za pomocą funkcji composable(), parametr NavBackStackEntry jest dostępny.

@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) }
}

Uwaga:

  • Trasa Profile określa miejsce docelowe początkowe na wykresie nawigacyjnym, przy czym argument "John Smith" to argument name.
  • Samo miejsce docelowe to blok composable<Profile>{}.
  • Funkcja kompozycyjna ProfileScreen przyjmuje wartość profile.name jako własny argument name.
  • W związku z tym wartość "John Smith" przekazuje się do ProfileScreen.

Przykład z minimalną ilością danych

Kompletny przykład współdziałania elementów 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 pokazuje fragment kodu, zamiast przekazywać NavController do funkcji kompozycyjnych, ujawniaj zdarzenie funkcji NavHost. Oznacza to, że obiekty kompozycyjne powinny mieć parametr typu () -> Unit, dla którego funkcja NavHost przekazuje funkcję lambda wywołującą NavController.navigate().

Fragmenty

Jak wspomnieliśmy w poprzednich sekcjach, gdy używasz fragmentów, możesz automatycznie utworzyć wykres nawigacyjny za pomocą narzędzia DSL, XML lub edytora Android Studio.

Szczegółowe informacje na ten temat znajdziesz w sekcjach poniżej.

Automatyzacja

Za pomocą technologii DSL Kotlin można w sposób zautomatyzowany tworzyć graf nawigacji z fragmentami. Jest to pod wieloma względami bardziej uporządkowane i nowoczesne niż użycie pliku zasobów XML.

Przyjrzyjmy się przykładowi, w którym zastosowano wykres nawigacji na 2 ekrany.

Najpierw musisz utworzyć NavHostFragment, który nie może zawierać elementu 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ż id z NavHostFragment do NavController.findNavController. Powiąże to element NavController z elementem NavHostFragment.

Następnie wywołanie NavController.createGraph() łączy wykres z tabelą NavController, a w konsekwencji także z tabelą 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.
}

Ten sposób korzystania z DSL jest bardzo podobny do przepływu pracy opisanego w poprzedniej sekcji Tworzenie. Na przykład zarówno tam, jak i tutaj funkcja NavController.createGraph() generuje NavGraph. Podobnie, mimo że NavGraphBuilder.composable() dodaje do wykresu miejsca docelowe kompozycyjne, tutaj NavGraphBuilder.fragment() dodaje miejsce docelowe dla fragmentu.

Więcej informacji o tym, jak korzystać z DSL Kotlin, znajdziesz w artykule Tworzenie wykresu za pomocą narzędzia NavGraphBuilder DSL.

XML

Kod XML możesz wpisać bezpośrednio samodzielnie. Poniższy przykład odzwierciedla i odnosi się do przykładu z 2 ekranami z poprzedniej sekcji.

Najpierw utwórz NavHostFragment. Służy on jako host nawigacji, który zawiera rzeczywisty wykres nawigacji.

Minimalna implementacja elementu 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>

NavHostFragment zawiera atrybut app:navGraph. Użyj tego atrybutu, aby połączyć wykres nawigacyjny z hostem nawigacji. Oto przykładowa implementacja 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>

Działają one do definiowania połączeń między różnymi miejscami docelowymi. W tym przykładzie fragment profile zawiera działanie, które prowadzi do strony friendslist. Więcej informacji znajdziesz w artykule Korzystanie z działań i fragmentów nawigacji.

Edytor

Możesz zarządzać wykresem nawigacji aplikacji, korzystając z edytora nawigacji w Android Studio. Jest to zasadniczo GUI, którego możesz użyć do utworzenia i edytowania pliku XML NavigationFragment, jak pokazano w poprzedniej sekcji.

Więcej informacji znajdziesz w sekcji Edytor nawigacji.

Wykresy zagnieżdżone

Możesz też używać wykresów zagnieżdżonych. Wiąże się to z wykorzystaniem wykresu jako miejsca docelowego nawigacji. Więcej informacji znajdziesz w artykule Wykresy zagnieżdżone.

Dalsza lektura

Więcej podstawowych pojęć związanych z nawigacją znajdziesz w tych przewodnikach:

  • Omówienie: przeczytaj ogólne omówienie komponentu Nawigacja.
  • Miejsca docelowe aktywności: przykłady implementacji miejsc docelowych, które przenoszą użytkownika do określonych działań.
  • Miejsca docelowe okien: przykłady tworzenia miejsc docelowych kierujących użytkownika do okna.
  • Nawigowanie do celu: szczegółowy przewodnik z informacjami o tym, jak dotrzeć z jednego miejsca docelowego do drugiego.
  • Wykresy zagnieżdżone: szczegółowy przewodnik na temat zagnieżdżania wykresów nawigacyjnych w obrębie innego.