Zagnieżdżone wykresy

Ścieżki logowania, kreatory i inne podścieżki w aplikacji najlepiej przedstawić jako zagnieżdżone wykresy nawigacji. Dzięki zagnieżdżaniu w ten sposób samodzielnych podścieżek nawigacji główna ścieżka interfejsu aplikacji jest łatwiejsza do zrozumienia i zarządzania.

Dodatkowo zagnieżdżone wykresy można ponownie wykorzystać. Zapewniają też pewien poziom hermetyzacji – miejsca docelowe poza zagnieżdżonym wykresem nie mają bezpośredniego dostępu do żadnego z miejsc docelowych w zagnieżdżonym wykresie. Zamiast tego powinny one navigate() do samego zagnieżdżonego wykresu, w którym logika wewnętrzna może zmieniać się bez wpływu na resztę wykresu.

Przykład

Wykres nawigacji najwyższego poziomu w aplikacji powinien zaczynać się od początkowego miejsca docelowego, które użytkownik widzi po uruchomieniu aplikacji, i zawierać miejsca docelowe, które widzi podczas korzystania z aplikacji.

Rysunek 1. Wykres nawigacji najwyższego poziomu.

Na przykładzie wykresu nawigacji najwyższego poziomu z rysunku 1 załóżmy, że chcesz wymagać, aby użytkownik widział ekrany title_screen i register tylko przy pierwszym uruchomieniu aplikacji. Następnie informacje o użytkowniku są przechowywane, a przy kolejnych uruchomieniach aplikacji użytkownik powinien być przenoszony bezpośrednio na ekran match.

Zalecamy ustawienie ekranu match jako początkowego miejsca docelowego wykresu nawigacji najwyższego poziomu i przeniesienie ekranów tytułu i rejestracji na zagnieżdżony wykres, jak pokazano na rysunku 1:

Rysunek 2. Wykres nawigacji najwyższego poziomu zawiera teraz zagnieżdżony wykres.

Po uruchomieniu ekranu dopasowania sprawdź, czy jest zarejestrowany użytkownik. Jeśli użytkownik nie jest zarejestrowany, przenieś go na ekran rejestracji.

Więcej informacji o scenariuszach nawigacji warunkowej znajdziesz w artykule Conditional navigation.

Utwórz

Aby utworzyć zagnieżdżony wykres nawigacji za pomocą Compose, użyj funkcji NavGraphBuilder.navigation(). Podczas dodawania miejsc docelowych do wykresu używasz navigation() tak samo jak NavGraphBuilder.composable() i NavGraphBuilder.dialog() funkcji.

Główna różnica polega na tym, że funkcja navigation tworzy zagnieżdżony wykres, a nie nowe miejsce docelowe. Następnie w lambdzie funkcji navigation() wywołujesz funkcje composable() i dialog(), aby dodać miejsca docelowe do zagnieżdżonego wykresu.

Zobacz, jak poniższy fragment kodu implementuje wykres na rysunku 2 za pomocą Compose:

// Routes
@Serializable object Title
@Serializable object Register

// Route for nested graph
@Serializable object Game

// Routes inside nested graph
@Serializable object Match
@Serializable object InGame
@Serializable object ResultsWinner
@Serializable object GameOver

NavHost(navController, startDestination = Title) {
   composable<Title> {
       TitleScreen(
           onPlayClicked = { navController.navigate(route = Register) },
           onLeaderboardsClicked = { /* Navigate to leaderboards */ }
       )
   }
   composable<Register> {
       RegisterScreen(
           onSignUpComplete = { navController.navigate(route = Game) }
       )
   }
   navigation<Game>(startDestination = Match) {
       composable<Match> {
           MatchScreen(
               onStartGame = { navController.navigate(route = InGame) }
           )
       }
       composable<InGame> {
           InGameScreen(
               onGameWin = { navController.navigate(route = ResultsWinner) },
               onGameLose = { navController.navigate(route = GameOver) }
           )
       }
       composable<ResultsWinner> {
           ResultsWinnerScreen(
               onNextMatchClicked = {
                   navController.navigate(route = Match) {
                       popUpTo(route = Match) { inclusive = true }
                   }
               },
               onLeaderboardsClicked = { /* Navigate to leaderboards */ }
           )
       }
       composable<GameOver> {
           GameOverScreen(
               onTryAgainClicked = {
                   navController.navigate(route = Match) {
                       popUpTo(route = Match) { inclusive = true }
                   }
               }
           )
       }
   }
}

Aby przejść bezpośrednio do zagnieżdżonego miejsca docelowego, użyj typu trasy tak jak w przypadku każdego innego miejsca docelowego. Wynika to z tego, że trasy są koncepcją globalną służącą do identyfikowania miejsc docelowych, do których można przejść z dowolnego ekranu:

navController.navigate(route = Match)
.

XML

Jeśli używasz XML, możesz utworzyć zagnieżdżony wykres za pomocą Edytora nawigacji. Aby to zrobić:

  1. W Edytorze nawigacji naciśnij i przytrzymaj klawisz Shift i kliknij miejsca docelowe, które chcesz uwzględnić w zagnieżdżonym wykresie.
  2. Kliknij prawym przyciskiem myszy, aby otworzyć menu kontekstowe, i wybierz Przenieś do zagnieżdżonego wykresu > Nowy wykres. Miejsca docelowe są umieszczone w zagnieżdżonym wykresie. Rysunek 2 przedstawia zagnieżdżony wykres w Edytorze nawigacji:

    Rysunek 2. Zagnieżdżony wykres w Edytorze nawigacji
  3. Kliknij zagnieżdżony wykres. W panelu Atrybuty pojawią się te atrybuty:

    • Typ, który zawiera "Zagnieżdżony wykres"
    • Identyfikator, który zawiera przypisany przez system identyfikator zagnieżdżonego wykresu. Ten identyfikator służy do odwoływania się do zagnieżdżonego wykresu w kodzie.
  4. Kliknij dwukrotnie zagnieżdżony wykres, aby wyświetlić jego miejsca docelowe.

  5. Kliknij kartę Tekst , aby przełączyć się na widok XML. Do wykresu został dodany zagnieżdżony wykres nawigacji. Ten wykres nawigacji ma własne elementy navigation, własny identyfikator i atrybut startDestination, który wskazuje pierwsze miejsce docelowe w zagnieżdżonym wykresie:

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:app="http://schemas.android.com/apk/res-auto"
       xmlns:tools="http://schemas.android.com/tools"
       xmlns:android="http://schemas.android.com/apk/res/android"
       app:startDestination="@id/mainFragment">
       <fragment
           android:id="@+id/mainFragment"
           android:name="com.example.cashdog.cashdog.MainFragment"
           android:label="fragment_main"
           tools:layout="@layout/fragment_main" >
           <action
               android:id="@+id/action_mainFragment_to_sendMoneyGraph"
               app:destination="@id/sendMoneyGraph" />
           <action
               android:id="@+id/action_mainFragment_to_viewBalanceFragment"
               app:destination="@id/viewBalanceFragment" />
       </fragment>
       <fragment
           android:id="@+id/viewBalanceFragment"
           android:name="com.example.cashdog.cashdog.ViewBalanceFragment"
           android:label="fragment_view_balance"
           tools:layout="@layout/fragment_view_balance" />
       <navigation android:id="@+id/sendMoneyGraph" app:startDestination="@id/chooseRecipient">
           <fragment
               android:id="@+id/chooseRecipient"
               android:name="com.example.cashdog.cashdog.ChooseRecipient"
               android:label="fragment_choose_recipient"
               tools:layout="@layout/fragment_choose_recipient">
               <action
                   android:id="@+id/action_chooseRecipient_to_chooseAmountFragment"
                   app:destination="@id/chooseAmountFragment" />
           </fragment>
           <fragment
               android:id="@+id/chooseAmountFragment"
               android:name="com.example.cashdog.cashdog.ChooseAmountFragment"
               android:label="fragment_choose_amount"
               tools:layout="@layout/fragment_choose_amount" />
       </navigation>
    </navigation>
    
  6. W kodzie przekaż identyfikator zasobu działania łączącego wykres główny z zagnieżdżonym wykresem:

Kotlin

view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph)

Java

Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
  1. Wróć do karty Projekt i kliknij Główny, aby wrócić do wykresu głównego.

Odniesienia do innych wykresów nawigacji za pomocą include

Innym sposobem na modularyzację struktury wykresu jest dołączenie jednego wykresu do drugiego za pomocą elementu <include> w nadrzędnym wykresie nawigacji. Dzięki temu dołączony wykres można zdefiniować w osobnym module lub projekcie, co maksymalizuje możliwość ponownego wykorzystania.

Poniższy fragment kodu pokazuje, jak używać elementu <include>:

<!-- (root) nav_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/fragment">

    <include app:graph="@navigation/included_graph" />

    <fragment
        android:id="@+id/fragment"
        android:name="com.example.myapplication.BlankFragment"
        android:label="Fragment in Root Graph"
        tools:layout="@layout/fragment_blank">
        <action
            android:id="@+id/action_fragment_to_second_graph"
            app:destination="@id/second_graph" />
    </fragment>

    ...
</navigation>
<!-- included_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/second_graph"
    app:startDestination="@id/includedStart">

    <fragment
        android:id="@+id/includedStart"
        android:name="com.example.myapplication.IncludedStart"
        android:label="fragment_included_start"
        tools:layout="@layout/fragment_included_start" />
</navigation>