Procesy logowania, kreatory lub inne podprocesy w aplikacji najlepiej przedstawiać jako zagnieżdżone wykresy nawigacji. Dzięki zagnieżdżaniu zamkniętych podprzepływów nawigacji w ten sposób główny przepływ interfejsu aplikacji jest łatwiejszy do zrozumienia i zarządzania.
Dodatkowo można ponownie używać zagnieżdżonych wykresów. Zapewniają też pewien poziom enkapsulacji – miejsca docelowe spoza zagnieżdżonego grafu nie mają bezpośredniego dostępu do żadnych miejsc docelowych w zagnieżdżonym grafie. Zamiast tego należy użyć funkcji navigate()
do samego zagnieżdżonego wykresu, gdzie logika wewnętrzna może się zmieniać bez wpływu na pozostałą część wykresu.
Przykład
Główny diagram nawigacji w aplikacji powinien zaczynać się od początkowego miejsca docelowego, które użytkownik widzi po uruchomieniu aplikacji, i obejmować miejsca docelowe, które widzi on podczas poruszania się po aplikacji.
Na przykładzie grafu nawigacji najwyższego poziomu na rysunku 1 załóżmy, że chcesz, aby użytkownik widział ekrany title_screen i register tylko wtedy, gdy aplikacja uruchamia się po raz pierwszy. Następnie informacje o użytkowniku są przechowywane, a przy kolejnych uruchamieniach aplikacji użytkownik powinien od razu przejść do ekranu dopasowania.
Zalecamy, aby ekran poszukiwania ustawić jako punkt początkowy w wykresie nawigacji najwyższego poziomu, a ekrany z tytułami i rejestracją przenieść do zagnieżdżonego wykresu, jak pokazano na rysunku 1:
Gdy pojawi się ekran dopasowania, sprawdź, czy jest zarejestrowany użytkownik. Jeśli użytkownik nie jest zarejestrowany, przekieruj go do ekranu rejestracji.
Więcej informacji o warunkowej nawigacji znajdziesz w artykule Warunkowa nawigacja.
Compose
Aby utworzyć zagnieżdżony graf nawigacji za pomocą Compose, użyj funkcji NavGraphBuilder.navigation()
. Podczas dodawania miejsc docelowych do grafu możesz używać funkcji navigation()
tak samo jak funkcji NavGraphBuilder.composable()
i NavGraphBuilder.dialog()
.
Główna różnica polega na tym, że funkcja navigation
tworzy zagnieżdżoną grafę, a nie nowe miejsce docelowe. Następnie w ramach funkcji lambda usługi navigation()
wywołujesz funkcje composable()
i dialog()
, aby dodać miejsca docelowe do grafu zagnieżdżonego.
Zwróć uwagę, jak ten fragment kodu tworzy wykres na rysunku 2 za pomocą usługi 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 dowolnego innego miejsca docelowego. Dzieje się tak, ponieważ trasy to pojęcie globalne służące do identyfikowania miejsc docelowych, do których można przejść z dowolnego ekranu:
navController.navigate(route = Match)
XML
Jeśli używasz pliku XML, możesz utworzyć zagnieżdżony graf za pomocą Edytora nawigacji. Aby to zrobić:
- W Edytorze nawigacji przytrzymaj klawisz Shift i kliknij miejsca docelowe, które chcesz uwzględnić w zagnieżdżonym wykresie.
Kliknij prawym przyciskiem myszy, aby otworzyć menu kontekstowe, i wybierz Przenieś do zagnieżdżonego wykresu > Nowy wykres. Miejsca docelowe są zamknięte w zagnieżdżonym wykresie. Rysunek 2. przedstawia zagnieżdżony wykres w Edytorze nawigacji:
Kliknij graf zagnieżdżony. W panelu Atrybuty pojawiają się te atrybuty:
- Typ, który zawiera „Grafikę zagnieżdżoną”.
- Identyfikator, który zawiera przypisany przez system identyfikator grafu zagnieżdżonego. Ten identyfikator służy do odwoływania się w kodzie do grafu zagnieżdżonego.
Kliknij dwukrotnie graf zagnieżdżony, aby wyświetlić jego miejsca docelowe.
Kliknij kartę Tekst, aby przełączyć się na widok XML. Do wykresu został dodany zagnieżdżony diagram nawigacji. Ten graf nawigacyjny ma własne elementy
navigation
, własny identyfikator i atrybutstartDestination
, który wskazuje na pierwszy element docelowy w grafu zagnieżdżonym:<?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>
W kodzie przekaż identyfikator zasobu działania, które łączy graf główny z grafem zagnieżdżonym:
Kotlin
view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph)
Java
Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
- Na karcie Projekt możesz wrócić do grafu głównego, klikając Root (Root).
Odwoływanie się do innych grafów nawigacji za pomocą include
Innym sposobem modułowego dzielenia struktury grafu jest uwzględnienie jednego grafu w innym za pomocą elementu <include>
w nadrzędnym grafie nawigacyjnym. Dzięki temu można zdefiniować zawarty graf w osobnym module lub projekcie, co zmaksymalizuje możliwość ponownego użycia.
Ten fragment kodu pokazuje, jak używać funkcji <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">
<strong><include app:graph="@navigation/included_graph" /></strong>
<fragment
android:id="@+id/fragment"
android:name="com.example.myapplication.BlankFragment"
android:label="Fragment in Root Graph"
tools:layout="@layout/fragment_blank">
<strong><action
android:id="@+id/action_fragment_to_second_graph"
app:destination="@id/second_graph" /></strong>
</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"
<strong>android:id="@+id/second_graph"</strong>
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>
Dodatkowe materiały
Więcej informacji o nawigacji znajdziesz w tych dodatkowych materiałach.