Un grafico di navigazione può essere costituito da una qualsiasi combinazione dei seguenti elementi:
- Una destinazione singola, ad esempio una destinazione
<fragment>
. - Un grafico nidificato che incapsula un insieme di destinazioni correlate.
- Un elemento
<include>
, che consente di incorporare un altro file di grafico di navigazione come se fosse nidificato.
Questa flessibilità ti consente di combinare grafici di navigazione più piccoli per formare il grafico di navigazione completo della tua app, anche se i grafici di navigazione più piccoli sono forniti da moduli separati.
Per gli esempi in questo argomento, ogni modulo di funzionalità è incentrato su una funzionalità e fornisce un singolo grafico di navigazione che incapsula tutte le destinazioni necessarie per implementare questa funzionalità. In un'app di produzione, potresti avere molti sottomoduli di livello inferiore che rappresentano i dettagli di implementazione di questo modulo delle funzionalità di livello superiore. Ciascuno di questi moduli delle funzionalità è incluso, direttamente o
indirettamente, nel tuo
modulo app
. L'applicazione multi-modulo di esempio utilizzata in questo documento ha la seguente struttura:
Ogni modulo funzionalità è un'unità autonoma con un proprio grafico di navigazione e destinazioni. Il modulo app
dipende da ciascun modulo e li aggiunge come dettagli di implementazione nel file build.gradle
, come mostrato di seguito:
Trendy
dependencies { ... implementation project(":feature:home") implementation project(":feature:favorites") implementation project(":feature:settings")
Kotlin
dependencies { ... implementation(project(":feature:home")) implementation(project(":feature:favorites")) implementation(project(":feature:settings"))
Il ruolo del modulo app
Il modulo app
ha la responsabilità di fornire il grafico completo della tua
app e di aggiungere NavHost
alla UI. Nel grafico di navigazione del modulo app
, puoi fare riferimento ai grafici delle librerie utilizzando <include>
. Sebbene <include>
sia funzionalmente come l'utilizzo di un grafico nidificato, <include>
supporta grafici di altri moduli di progetto o di progetti di biblioteche, come mostrato nell'esempio seguente:
<?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/home_nav_graph">
<include app:graph="@navigation/home_navigation" />
<include app:graph="@navigation/favorites_navigation" />
<include app:graph="@navigation/settings_navigation" />
</navigation>
Una volta inclusa una libreria nel grafico di navigazione di primo livello, puoi spostarti nei grafici della libreria, se necessario. Ad esempio, potresti creare un'azione per accedere al grafico delle impostazioni da un frammento del grafico di navigazione, come mostrato di seguito:
<?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/home_nav_graph">
<include app:graph="@navigation/home_navigation" />
<include app:graph="@navigation/favorites_navigation" />
<include app:graph="@navigation/settings_navigation" />
<fragment
android:id="@+id/random_fragment"
android:name="com.example.android.RandomFragment"
android:label="@string/fragment_random" >
<!-- Launch into Settings Navigation Graph -->
<action
android:id="@+id/action_random_fragment_to_settings_nav_graph"
app:destination="@id/settings_nav_graph" />
</fragment>
</navigation>
Quando più moduli delle funzionalità devono fare riferimento a un insieme comune di destinazioni, ad esempio un grafico di accesso, non devi includere queste destinazioni comuni nel grafico di navigazione di ciascun modulo delle funzionalità. Aggiungi invece le destinazioni comuni al grafico di navigazione del modulo app
.
Ogni modulo delle funzionalità può quindi navigare tra i moduli delle caratteristiche per raggiungere le destinazioni comuni.
Nell'esempio precedente, l'azione specifica una destinazione di navigazione
di @id/settings_nav_graph
. Questo ID si riferisce a una destinazione
definita nel grafico incluso @navigation/settings_navigation.
Navigazione di primo livello nel modulo dell'app
Il componente Navigazione include una classe NavigationUI
.
Questa classe contiene metodi statici che gestiscono la navigazione con la barra
delle app in alto, il riquadro di navigazione a scomparsa e la navigazione in basso. Se le destinazioni di primo livello dell'app sono composte da elementi UI forniti da moduli di funzionalità, nel modulo app
puoi inserire gli elementi dell'interfaccia utente e di navigazione di primo livello. Poiché il modulo dell'app dipende dai moduli delle funzionalità che collaborano, tutte le destinazioni sono accessibili dal codice definito all'interno del modulo dell'app. Ciò significa che puoi utilizzare
NavigationUI
per
collegare le destinazioni alle voci di menu
se l'ID dell'articolo corrisponde all'ID di una destinazione.
Nella Figura 2, il modulo app
di esempio definisce un elemento
BottomNavigationView
nella sua attività principale. Gli ID delle voci di menu nel menu corrispondono agli ID dei grafici di navigazione dei grafici delle librerie:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@id/home_nav_graph"
android:icon="@drawable/ic_home"
android:title="Home"
app:showAsAction="ifRoom"/>
<item
android:id="@id/favorites_nav_graph"
android:icon="@drawable/ic_favorite"
android:title="Favorites"
app:showAsAction="ifRoom"/>
<item
android:id="@id/settings_nav_graph"
android:icon="@drawable/ic_settings"
android:title="Settings"
app:showAsAction="ifRoom" />
</menu>
Per consentire a NavigationUI
di gestire la
navigazione in basso, chiama
setupWithNavController()
da onCreate()
nel tuo corso di attività principale, come mostrato nel seguente
esempio:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController findViewById<BottomNavigationView>(R.id.bottom_nav) .setupWithNavController(navController) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); NavHostFragment navHostFragment = (NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment); NavController navController = navHostFragment.getNavController(); BottomNavigationView bottomNav = findViewById(R.id.bottom_nav); NavigationUI.setupWithNavController(bottomNav, navController); }
Una volta inserito questo codice, NavigationUI
passa al grafico della libreria appropriato quando l'utente fa clic su un elemento di navigazione nella parte inferiore.
Tieni presente che in genere è una cattiva pratica che il tuo modulo dell'app abbia una dipendenza rigida da una destinazione specifica incorporata in profondità nel grafico di navigazione dei moduli delle funzionalità. Nella maggior parte dei casi è consigliabile che il modulo dell'app conosca solo il punto di accesso a eventuali grafici di navigazione incorporati o inclusi (questo si applica anche al di fuori dei moduli delle funzionalità). Se devi inserire un link a una destinazione che si trova all'interno del grafico di navigazione della libreria, il modo migliore per farlo è utilizzare un link diretto. I link diretti sono anche l'unico modo in cui una libreria può raggiungere una destinazione nel grafico di navigazione di un'altra libreria.
Spostarsi tra i moduli delle funzionalità
Al momento della compilazione, i moduli delle funzionalità indipendenti non sono visibili, quindi non puoi utilizzare gli ID per passare alle destinazioni in altri moduli. Utilizza un link diretto per passare direttamente a una destinazione associata a un link diretto implicito.
Proseguendo con l'esempio precedente, immagina di dover passare da un pulsante nel
modulo :feature:home
a una destinazione nidificata nel
modulo :feature:settings
. A questo scopo, aggiungi un link diretto alla destinazione nel grafico di navigazione delle impostazioni, come mostrato di seguito:
<?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/settings_nav_graph"
app:startDestination="@id/settings_fragment_one">
...
<fragment
android:id="@+id/settings_fragment_two"
android:name="com.example.google.login.SettingsFragmentTwo"
android:label="@string/settings_fragment_two" >
<deepLink
app:uri="android-app://example.google.app/settings_fragment_two" />
</fragment>
</navigation>
Quindi aggiungi il codice seguente al onClickListener
del pulsante nel frammento
home:
Kotlin
button.setOnClickListener { val request = NavDeepLinkRequest.Builder .fromUri("android-app://example.google.app/settings_fragment_two".toUri()) .build() findNavController().navigate(request) }
Java
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { NavDeepLinkRequest request = NavDeepLinkRequest.Builder .fromUri(Uri.parse("android-app://example.google.app/settings_fragment_two")) .build(); NavHostFragment.findNavController(this).navigate(request); } });
A differenza della navigazione usando ID azione o destinazione, puoi accedere a qualsiasi URI di qualsiasi grafico, anche tra moduli.
Durante la navigazione utilizzando l'URI, lo stack di backup non viene reimpostato. Questo comportamento è diverso dalla navigazione con link diretti espliciti, in cui lo stack posteriore viene sostituito durante la navigazione.