Eine Navigationsgrafik kann aus einer beliebigen Kombination der folgenden Elemente bestehen:
- Ein einzelnes Ziel, z. B. ein
<fragment>
-Ziel. - Ein verschachtelter Graph, der eine Reihe zusammengehöriger Ziele einschließt.
- Ein
<include>
-Element, mit dem Sie eine andere Navigationsgrafikdatei so einbetten können, als wäre sie verschachtelt.
Mit dieser Flexibilität können Sie kleinere Navigationsdiagramme kombinieren, um die vollständige Navigationsgrafik Ihrer App zu bilden, auch wenn diese kleineren Navigationsdiagramme über separate Module bereitgestellt werden.
In den Beispielen in diesem Thema konzentriert sich jedes Funktionsmodul auf ein Feature und stellt eine einzelne Navigationsgrafik bereit, die alle Ziele enthält, die zur Implementierung dieses Features erforderlich sind. In einer Produktions-App gibt es möglicherweise viele untergeordnete Module auf einer niedrigeren Ebene, bei denen es sich um Implementierungsdetails dieses übergeordneten Funktionsmoduls handelt. Alle diese Funktionsmodule sind entweder direkt oder indirekt in Ihrem app
-Modul enthalten. Die in diesem Dokument verwendete Beispiel-Anwendung mit mehreren Modulen hat die folgende Struktur:
Jedes Funktionsmodul ist eine eigenständige Einheit mit einer eigenen Navigationsgrafik und eigenen Zielen. Das Modul app
ist von jedem Modul abhängig und fügt es wie hier gezeigt als Implementierungsdetails in der Datei build.gradle
hinzu:
Groovig
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"))
Die Rolle des app
-Moduls
Das Modul app
stellt das vollständige Diagramm für Ihre Anwendung bereit und fügt das NavHost
in Ihre UI ein. Im Navigationsdiagramm des Moduls app
können Sie mithilfe von <include>
auf die Bibliotheksdiagramme verweisen. Die Verwendung von <include>
funktioniert funktional genauso wie eine verschachtelte Grafik. <include>
unterstützt jedoch Grafiken aus anderen Projektmodulen oder Bibliotheksprojekten, wie im folgenden Beispiel gezeigt:
<?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>
Sobald eine Bibliothek in die Navigationsgrafik auf oberster Ebene aufgenommen wurde, können Sie nach Bedarf zu den Bibliotheksdiagrammen navigieren. Sie können beispielsweise eine Aktion erstellen, um von einem Fragment in der Navigationsgrafik zum Einstellungsdiagramm zu wechseln:
<?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>
Wenn mehrere Featuremodule auf einen gemeinsamen Satz von Zielen verweisen müssen, z. B. eine Anmeldegrafik, sollten Sie diese gemeinsamen Ziele nicht in die Navigationsgrafik der einzelnen Featuremodule aufnehmen. Stattdessen können Sie diese häufigen Ziele dem Navigationsdiagramm des app
-Moduls hinzufügen.
Jedes Featuremodul kann dann durch die Featuremodule navigieren, um zu diesen gängigen Zielen zu gelangen.
Im vorherigen Beispiel gibt die Aktion das Navigationsziel @id/settings_nav_graph
an. Diese ID bezieht sich auf ein Ziel, das im enthaltenen Diagramm @navigation/settings_navigation.
definiert ist
Navigation der obersten Ebene im App-Modul
Die Navigationskomponente enthält eine NavigationUI
-Klasse.
Diese Klasse enthält statische Methoden, die die Navigation über die obere App-Leiste, die Navigationsleiste und die Navigation am unteren Rand verwalten. Wenn die Ziele Ihrer App auf oberster Ebene aus UI-Elementen bestehen, die von Funktionsmodulen bereitgestellt werden, ist das Modul app
ein idealer Ort, um die Navigations- und UI-Elemente der obersten Ebene zu platzieren. Da das Anwendungsmodul von den gemeinsam verwendeten Funktionsmodulen abhängt, können Sie über Code, der in Ihrem Anwendungsmodul definiert wurde, auf alle Ziele zugreifen. Das bedeutet, dass Sie NavigationUI
verwenden können, um Ziele mit Menüpunkten zu verknüpfen, wenn die ID des Elements mit der ID eines Ziels übereinstimmt.
In Abbildung 2 definiert das Beispielmodul app
ein BottomNavigationView
in seiner Hauptaktivität. Die Menüelement-IDs im Menü stimmen mit den Navigationsdiagramm-IDs der Bibliotheksgrafiken überein:
<?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>
Damit NavigationUI
die Navigation unten verarbeiten kann, rufen Sie setupWithNavController()
von onCreate()
in Ihrer Hauptaktivitätsklasse auf, wie im folgenden Beispiel gezeigt:
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); }
Mit diesem Code ruft NavigationUI
das entsprechende Bibliotheksdiagramm auf, wenn der Nutzer auf ein unteres Navigationselement klickt.
Es ist generell nicht empfehlenswert, wenn Ihr App-Modul eine starke Abhängigkeit von einem bestimmten Ziel hat, das tief in die Navigationsgrafik Ihrer Feature-Module eingebettet ist. In den meisten Fällen sollte Ihr Anwendungsmodul nur den Einstiegspunkt für eingebettete oder enthaltene Navigationsdiagramme kennen (dies gilt auch außerhalb von Funktionsmodulen). Wenn Sie auf ein Ziel verlinken müssen, das tief in der Navigationsgrafik Ihrer Bibliothek enthalten ist, verwenden Sie am besten einen Deeplink. Deeplinks sind außerdem die einzige Möglichkeit für eine Bibliothek, zu einem Ziel in der Navigationsgrafik einer anderen Bibliothek zu gelangen.
Zwischen Funktionsmodule wechseln
Zum Zeitpunkt der Kompilierung können unabhängige Featuremodule einander nicht sehen. Daher können Sie IDs nicht verwenden, um zu Zielen in anderen Modulen zu navigieren. Verwenden Sie stattdessen einen Deeplink, um direkt zu einem Ziel zu gelangen, das mit einem impliziten Deeplink verknüpft ist.
Ausgehend vom vorherigen Beispiel stellen Sie sich vor, Sie müssen von einer Schaltfläche im Modul :feature:home
zu einem Ziel navigieren, das im Modul :feature:settings
verschachtelt ist. Fügen Sie dazu in der Navigationsgrafik für die Einstellungen einen Deeplink zum Ziel hinzu, wie hier gezeigt:
<?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>
Fügen Sie dann den folgenden Code in das onClickListener
der Schaltfläche im Home-Fragment ein:
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); } });
Im Gegensatz zur Navigation mithilfe von Aktions- oder Ziel-IDs können Sie jeden URI in einer Grafik aufrufen, auch modulübergreifend.
Beim Navigieren mit URI wird der Back-Stack nicht zurückgesetzt. Dieses Verhalten unterscheidet sich von der expliziten Deeplink-Navigation, bei der beim Navigieren der Back Stack ersetzt wird.