Die Navigationskomponente ist ein die komplexe Navigation, Übergangsanimationen, Deeplinks und das Argument mit der Kompilierungszeit, das zwischen den Bildschirmen in Ihrer App übergeben wird.
Dieses Dokument dient als allgemeiner Leitfaden für die Migration einer vorhandenen Anwendung zu Navigationskomponente nutzen.
Auf übergeordneter Ebene umfasst die Migration folgende Schritte:
Bildschirmspezifische UI-Logik aus Aktivitäten verschieben: Verschieben Sie die Benutzeroberfläche Ihrer App. Logik aus Aktivitäten heraus, sodass jede Aktivität nur die Logik globale Navigations-UI-Komponenten wie z. B.
Toolbar
erstellen, während Sie die Implementierung jedes Bildschirms in ein Fragment oder ein benutzerdefiniertes Ziel.Integration der Navigationskomponente: Erstellen Sie für jede Aktivität eine Navigationsdiagramm, das ein oder mehrere von diesem verwalteten Fragment enthält Aktivitäten. Ersetzen Sie Fragmenttransaktionen durch Vorgänge der Navigationskomponente.
Aktivitätsziele hinzufügen:
startActivity()
Anrufe ersetzen durch Aktionen mithilfe von Aktivitätszielen.Aktivitäten kombinieren – Kombinieren Sie Navigationsdiagramme in Fällen, in denen mehrere Aktivitäten ein gemeinsames Layout haben.
Voraussetzungen
In diesem Leitfaden wird davon ausgegangen, dass Sie Ihre Anwendung bereits für die Verwendung von AndroidX-Bibliotheken. Falls noch nicht geschehen, Ihr Projekt migrieren, um AndroidX vorher zu verwenden wird fortgesetzt.
Bildschirmspezifische Benutzeroberflächenlogik aus Aktivitäten verschieben
Aktivitäten sind Komponenten auf Systemebene, die eine grafische Interaktion ermöglichen. zwischen deiner App und Android. Aktivitäten werden im Manifest deiner App registriert damit Android weiß, welche Aktivitäten für den Start verfügbar sind. Die Aktivität kann Ihre App auch auf Android-Änderungen reagieren, z. B. auf die Benutzeroberfläche der App in den Vordergrund eintritt oder diesen verlässt, sich dreht usw. Die Aktivitäten können auch als Ort dienen, Bildschirmfreigaben.
Im Kontext Ihrer App sollten Aktivitäten als Host für die Navigation dienen. und die Logik und das Wissen für den Wechsel zwischen Bildschirmen enthalten, Daten weitergeben usw. Es ist jedoch besser, die Details Ihrer Benutzeroberfläche zu verwalten. in einen kleineren, wiederverwendbaren Teil Ihrer Benutzeroberfläche einfügen. Die empfohlene Implementierung Muster sind Fragmente. Weitere Informationen finden Sie unter Einzelne Aktivität: Warum, wann und wie erfahren Sie mehr über die Vorteile von Fragmenten. Die Navigation unterstützt Fragmente über die Abhängigkeit navigation-fragment. Navigation unterstützt auch benutzerdefinierten Zieltypen.
Wenn Ihre Anwendung keine Fragmente verwendet, müssen Sie als Erstes migrieren für jeden Bildschirm Ihrer App ein Fragment. Sie entfernen die Aktivität nicht unter Punkt zu kommen. Stattdessen erstellen Sie ein Fragment, das den Bildschirm repräsentiert und den Ihre UI-Logik nach Verantwortung differenzieren.
Jetzt neu: Fragmente
Beginnen wir mit einem Beispiel, um den Prozess der Einführung von Fragmenten zu veranschaulichen. einer Anwendung, die aus zwei Bildschirmen besteht: einem Bildschirm mit einer Produktliste und einem mit den Produktdetails. Durch Klicken auf ein Produkt auf dem Listenbildschirm zu einem Bildschirm mit Details, um mehr über das Produkt zu erfahren.
In diesem Beispiel sind die Bildschirme „Liste“ und „Details“ derzeit separate Aktivitäten.
Neues Layout für das Hosten der Benutzeroberfläche erstellen
Um ein Fragment einzuführen, erstellen Sie zunächst eine neue Layoutdatei für die Aktivität, zum Hosten des Fragments. Dadurch wird das aktuelle Layout der Inhaltsansicht der Aktivität ersetzt.
Für eine einfache Ansicht können Sie ein FrameLayout
verwenden, wie im Folgenden gezeigt.
Beispiel product_list_host
:
<FrameLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_content"
android:layout_height="match_parent"
android:layout_width="match_parent" />
Das Attribut id
bezieht sich auf den Inhaltsabschnitt, in dem wir später
Fragment.
Ändern Sie als Nächstes in der Funktion onCreate()
Ihrer Aktivität die Layoutdatei-Referenz.
, um auf diese neue Layoutdatei zu verweisen:
Kotlin
class ProductListActivity : AppCompatActivity() { ... override fun onCreate(savedInstanceState: Bundle?) { ... // Replace setContentView(R.layout.product_list) with the line below setContentView(R.layout.product_list_host) ... } }
Java
public class ProductListActivity extends AppCompatActivity { ... @Override public void onCreate(@Nullable Bundle savedInstanceState) { ... // Replace setContentView(R.layout.product_list); with the line below setContentView(R.layout.product_list_host); ... } }
Das vorhandene Layout (in diesem Beispiel product_list
) wird als Stammansicht verwendet.
für das Fragment, das Sie erstellen möchten.
Fragment erstellen
Erstellen Sie ein neues Fragment, um die Benutzeroberfläche für Ihren Bildschirm zu verwalten. Es empfiehlt sich,
mit dem Hostnamen Ihrer Aktivität übereinstimmen. Im folgenden Snippet wird
ProductListFragment
, z. B.:
Kotlin
class ProductListFragment : Fragment() { // Leave empty for now. }
Java
public class ProductListFragment extends Fragment { // Leave empty for now. }
Aktivitätslogik in ein Fragment verschieben
Nach der Fragmentdefinition besteht der nächste Schritt darin, die UI-Logik für
aus der Aktivität
in dieses neue Fragment übertragen. Wenn Sie aus einem
eine aktivitätsbasierte Architektur verwenden,
in der onCreate()
-Funktion Ihrer Aktivität.
Hier ist ein Beispiel für einen aktivitätsbasierten Bildschirm mit UI-Logik, den wir verschieben müssen:
Kotlin
class ProductListActivity : AppCompatActivity() { // Views and/or ViewDataBinding references, Adapters... private lateinit var productAdapter: ProductAdapter private lateinit var binding: ProductListActivityBinding ... // ViewModels, System Services, other Dependencies... private val viewModel: ProductListViewModel by viewModels() ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // View initialization logic DataBindingUtil.setContentView(this, R.layout.product_list_activity) // Post view initialization logic // Connect adapters productAdapter = ProductAdapter(productClickCallback) binding.productsList.setAdapter(productAdapter) // Initialize view properties, set click listeners, etc. binding.productsSearchBtn.setOnClickListener {...} // Subscribe to state viewModel.products.observe(this, Observer { myProducts -> ... }) // ...and so on } ... }
Java
public class ProductListActivity extends AppCompatActivity { // Views and/or ViewDataBinding references, adapters... private ProductAdapter productAdapter; private ProductListActivityBinding binding; ... // ViewModels, system services, other dependencies... private ProductListViewModel viewModel; ... @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // View initialization logic DataBindingUtil.setContentView(this, R.layout.product_list_activity); // Post view initialization logic // Connect adapters productAdapter = new ProductAdapter(productClickCallback); binding.productsList.setAdapter(productAdapter); // Initialize ViewModels and other dependencies ProductListViewModel viewModel = new ViewModelProvider(this).get(ProductListViewModel.java); // Initialize view properties, set click listeners, etc. binding.productsSearchBtn.setOnClickListener(v -> { ... }); // Subscribe to state viewModel.getProducts().observe(this, myProducts -> ... ); // ...and so on }
Ihre Aktivitäten können auch steuern, wann und wie Nutzende zur nächsten Bildschirm aus, wie im folgenden Beispiel gezeigt:
Kotlin
// Provided to ProductAdapter in ProductListActivity snippet. private val productClickCallback = ProductClickCallback { product -> show(product) } fun show(product: Product) { val intent = Intent(this, ProductActivity::class.java) intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.id) startActivity(intent) }
Java
// Provided to ProductAdapter in ProductListActivity snippet. private ProductClickCallback productClickCallback = this::show; private void show(Product product) { Intent intent = new Intent(this, ProductActivity.class); intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.getId()); startActivity(intent); }
Innerhalb Ihres Fragments verteilen Sie diese Arbeit zwischen
onCreateView()
und
onViewCreated()
,
wobei nur die Navigationslogik in der Aktivität verbleibt:
Kotlin
class ProductListFragment : Fragment() { private lateinit var binding: ProductListFragmentBinding private val viewModel: ProductListViewModel by viewModels() // View initialization logic override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { binding = DataBindingUtil.inflate( inflater, R.layout.product_list, container, false ) return binding.root } // Post view initialization logic override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // Connect adapters productAdapter = ProductAdapter(productClickCallback) binding.productsList.setAdapter(productAdapter) // Initialize view properties, set click listeners, etc. binding.productsSearchBtn.setOnClickListener {...} // Subscribe to state viewModel.products.observe(this, Observer { myProducts -> ... }) // ...and so on } // Provided to ProductAdapter private val productClickCallback = ProductClickCallback { product -> if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { (requireActivity() as ProductListActivity).show(product) } } ... }
Java
public class ProductListFragment extends Fragment { private ProductAdapter productAdapter; private ProductListFragmentBinding binding; // View initialization logic @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = DataBindingUtil.inflate( inflater, R.layout.product_list_fragment, container, false); return binding.getRoot(); } // Post view initialization logic @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { // Connect adapters binding.productsList.setAdapter(productAdapter); // Initialize ViewModels and other dependencies ProductListViewModel viewModel = new ViewModelProvider(this) .get(ProductListViewModel.class); // Initialize view properties, set click listeners, etc. binding.productsSearchBtn.setOnClickListener(...) // Subscribe to state viewModel.getProducts().observe(this, myProducts -> { ... }); // ...and so on // Provided to ProductAdapter private ProductClickCallback productClickCallback = new ProductClickCallback() { @Override public void onClick(Product product) { if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { ((ProductListActivity) requireActivity()).show(product); } } }; ... }
Beachten Sie, dass in ProductListFragment
kein Aufruf an
setContentView()
um das Layout zu erweitern und zu verbinden. In einem Fragment initialisiert onCreateView()
das Objekt
Stammansicht. onCreateView()
nimmt eine Instanz eines
LayoutInflater
, mit dem Sie
die Stammansicht basierend auf einer Layout-Ressourcendatei in die Höhe treiben. In diesem Beispiel wird der Parameter
Vorhandenes product_list
-Layout, das von der Aktivität verwendet wurde, da nichts
das Layout selbst ändern muss.
Wenn du UI-Logik in den onStart()
, onResume()
,
onPause()
oder onStop()
, die nicht mit der Navigation zusammenhängen, können Sie
verschieben Sie diese in entsprechende Funktionen mit demselben Namen im Fragment.
Fragment in der Hostaktivität initialisieren
Nachdem Sie die gesamte UI-Logik nach unten in das Fragment verschoben haben, Logik in der Aktivität bleiben.
Kotlin
class ProductListActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.product_list_host) } fun show(product: Product) { val intent = Intent(this, ProductActivity::class.java) intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.id) startActivity(intent) } }
Java
public class ProductListActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.product_list_host); } public void show(Product product) { Intent intent = new Intent(this, ProductActivity.class); intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.getId()); startActivity(intent); } }
Im letzten Schritt erstellen Sie eine Instanz des Fragments in onCreate()
,
nachdem Sie die Inhaltsansicht festgelegt haben:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.product_list_host) if (savedInstanceState == null) { val fragment = ProductListFragment() supportFragmentManager .beginTransaction() .add(R.id.main_content, fragment) .commit() } }
Java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.product_list_host); if (savedInstanceState == null) { ProductListFragment fragment = new ProductListFragment(); getSupportFragmentManager() .beginTransaction() .add(R.id.main_content, fragment) .commit(); } }
Wie in diesem Beispiel gezeigt, speichert FragmentManager
die Daten automatisch
Vorrang vor Konfigurationsänderungen. Sie müssen das Fragment also nur hinzufügen,
savedInstanceState
ist null.
Intent-Extras an das Fragment übergeben
Wenn Ihre Aktivität Extras
über einen Intent empfängt, können Sie diese an den
direkt als Argumente fragmentieren.
In diesem Beispiel erhält der ProductDetailsFragment
seine Argumente direkt
aus den Intent-Extras der Aktivität entfernen:
Kotlin
... if (savedInstanceState == null) { val fragment = ProductDetailsFragment() // Intent extras and Fragment Args are both of type android.os.Bundle. fragment.arguments = intent.extras supportFragmentManager .beginTransaction() .add(R.id.main_content, fragment) .commit() } ...
Java
... if (savedInstanceState == null) { ProductDetailsFragment fragment = new ProductDetailsFragment(); // Intent extras and fragment Args are both of type android.os.Bundle. fragment.setArguments(getIntent().getExtras()); getSupportFragmentManager() .beginTransaction() .add(R.id.main_content, fragment) .commit(); } ...
Jetzt sollten Sie die Ausführung Ihrer App mit dem ersten Bildschirm testen können. zur Verwendung eines Fragments aktualisiert. Migration der restlichen aktivitätsbasierten Bildschirmen und nehmen Sie sich Zeit, nach jeder Iteration zu testen.
Navigationskomponente einbinden
Sobald Sie eine fragmentierte Architektur verwenden, können Sie mit der Integration der Navigationskomponente beginnen.
Fügen Sie Ihrem Projekt zuerst die neuesten Navigationsabhängigkeiten hinzu, die Anweisungen im Versionshinweise zur Navigationsbibliothek
Navigationsdiagramm erstellen
Die Komponente „Navigation“ stellt die Navigationskonfiguration Ihrer App in einem Ressourcendatei als Grafik, ähnlich wie die Aufrufe Ihrer App. Das hilft, die Navigation Ihrer App außerhalb Ihrer Codebasis organisieren und damit Sie Ihre App-Navigation visuell bearbeiten können.
Um ein Navigationsdiagramm zu erstellen, erstellen Sie zuerst einen neuen Ressourcenordner mit dem Namen
navigation
Klicken Sie zum Hinzufügen der Grafik mit der rechten Maustaste auf dieses Verzeichnis und wählen Sie
Neu > Datei mit Navigationsressourcen.
Die Komponente „Navigation“ verwendet eine Aktivität als
Host für Navigation
und tauscht einzelne Fragmente in diesen Host aus, während sich Ihre Nutzer
für Ihre App. Bevor Sie damit beginnen können, die Navigation Ihrer App visuell zu organisieren,
müssen Sie eine NavHost
in der Aktivität konfigurieren, die
Diagramm. Da wir Fragmente verwenden, können wir die Navigationskomponente
Standardimplementierung von NavHost
,
NavHostFragment
Eine NavHostFragment
wird über einen FragmentContainerView
konfiguriert
innerhalb einer Hostaktivität platziert werden, wie im folgenden Beispiel gezeigt:
<androidx.fragment.app.FragmentContainerView
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/product_list_graph"
app:defaultNavHost="true"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Das Attribut app:NavGraph
verweist auf die zugehörige Navigationsgrafik.
Navigations-Host. Durch Festlegen dieser Eigenschaft wird die Navigationsgrafik aufgebläht und die Grafik festgelegt
auf der NavHostFragment
. Das Attribut app:defaultNavHost
sorgt dafür,
dass dein NavHostFragment
die Zurück-Taste des Systems abfängt.
Wenn Sie die Navigation der obersten Ebene verwenden, z. B. DrawerLayout
oder
BottomNavigationView
, dieses FragmentContainerView
ersetzt das Hauptelement der Inhaltsansicht. Weitere Informationen finden Sie unter
UI-Komponenten mit NavigationUI aktualisieren
.
Für ein einfaches Layout können Sie diesen FragmentContainerView
einfügen.
-Element als untergeordnetes Element des Stamms ViewGroup
:
<FrameLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/main_content"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/product_list_graph"
app:defaultNavHost="true"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Wenn Sie unten auf den Tab Design klicken, sollten Sie ein ähnliches Diagramm sehen.
mit dem unten angezeigten. Klicken Sie oben links in der Grafik
Ziele können Sie im Formular einen Verweis auf die NavHost
-Aktivität sehen.
von layout_name (resource_id)
.
Klicken Sie auf das Pluszeichen oben, um dem Diagramm Ihre Fragmente hinzuzufügen.
Bei der Komponente „Navigation“ werden einzelne Bildschirme als Ziele bezeichnet. Ziele können Fragmente, Aktivitäten oder benutzerdefinierte Ziele sein. Sie können beliebige Ziel in die Grafik aufnehmen. Aktivitätsziele sind jedoch werden als Terminalziele betrachtet, da Sie, wenn Sie zu einer Aktivität navigieren, Ziel ist es, innerhalb eines separaten Navigationshosts und einer separaten Grafik zu arbeiten.
Die Navigationskomponente bezieht sich darauf, wie Nutzende von einer Ziel als Aktionen zu einem anderen Ziel hinzufügen. Aktionen können auch eine Umstellung beschreiben Animationen und Popverhalten.
Fragmenttransaktionen entfernen
Wenn Sie nun die Navigationskomponente verwenden und zwischen fragmentierten Bildschirmen innerhalb derselben Aktivität navigieren, können Sie
FragmentManager
Interaktionen.
Wenn Ihre App mehrere Fragmente unter derselben Aktivität oder auf oberster Ebene verwendet
z. B. eine Navigationsleiste am unteren Rand,
mit FragmentManager
und
FragmentTransactions
um Fragmente im Hauptinhaltsbereich deiner Benutzeroberfläche hinzuzufügen oder zu ersetzen. Dies kann jetzt
ersetzt und mithilfe der Navigationskomponente vereinfacht werden, indem Aktionen
können Sie Ziele in der Grafik verknüpfen und dann mithilfe der
NavController
Hier sind einige mögliche Szenarien und die mögliche Vorgehensweise, Migration für jedes Szenario.
Einzelne Aktivität zum Verwalten mehrerer Fragmente
Wenn Sie eine einzelne Aktivität haben, die mehrere Fragmente verwaltet, ist Ihre Aktivität könnte wie folgt aussehen:
Kotlin
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Logic to load the starting destination // when the Activity is first created if (savedInstanceState == null) { val fragment = ProductListFragment() supportFragmentManager.beginTransaction() .add(R.id.fragment_container, fragment, ProductListFragment.TAG) .commit() } } // Logic to navigate the user to another destination. // This may include logic to initialize and set arguments on the destination // fragment or even transition animations between the fragments (not shown here). fun navigateToProductDetail(productId: String) { val fragment = new ProductDetailsFragment() val args = Bundle().apply { putInt(KEY_PRODUCT_ID, productId) } fragment.arguments = args supportFragmentManager.beginTransaction() .addToBackStack(ProductDetailsFragment.TAG) .replace(R.id.fragment_container, fragment, ProductDetailsFragment.TAG) .commit() } }
Java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Logic to load the starting destination when the activity is first created. if (savedInstanceState == null) { val fragment = ProductListFragment() supportFragmentManager.beginTransaction() .add(R.id.fragment_container, fragment, ProductListFragment.TAG) .commit(); } } // Logic to navigate the user to another destination. // This may include logic to initialize and set arguments on the destination // fragment or even transition animations between the fragments (not shown here). public void navigateToProductDetail(String productId) { Fragment fragment = new ProductDetailsFragment(); Bundle args = new Bundle(); args.putInt(KEY_PRODUCT_ID, productId); fragment.setArguments(args); getSupportFragmentManager().beginTransaction() .addToBackStack(ProductDetailsFragment.TAG) .replace(R.id.fragment_container, fragment, ProductDetailsFragment.TAG) .commit(); } }
Innerhalb des Quellziels rufen Sie möglicherweise eine Navigationsfunktion in auf ein Ereignis reagieren:
Kotlin
class ProductListFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // In this example a callback is passed to respond to an item clicked // in a RecyclerView productAdapter = ProductAdapter(productClickCallback) binding.productsList.setAdapter(productAdapter) } ... // The callback makes the call to the activity to make the transition. private val productClickCallback = ProductClickCallback { product -> (requireActivity() as MainActivity).navigateToProductDetail(product.id) } }
Java
public class ProductListFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { // In this example a callback is passed to respond to an item clicked in a RecyclerView productAdapter = new ProductAdapter(productClickCallback); binding.productsList.setAdapter(productAdapter); } ... // The callback makes the call to the activity to make the transition. private ProductClickCallback productClickCallback = product -> ( ((MainActivity) requireActivity()).navigateToProductDetail(product.getId()) ); }
Sie können dies ersetzen, indem Sie die Navigationsgrafik das Startziel und Aktionen zum Verknüpfen Ihrer Ziele und Argumente, wo erforderlich:
<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/product_list_graph"
app:startDestination="@id/product_list">
<fragment
android:id="@+id/product_list"
android:name="com.example.android.persistence.ui.ProductListFragment"
android:label="Product List"
tools:layout="@layout/product_list">
<action
android:id="@+id/navigate_to_product_detail"
app:destination="@id/product_detail" />
</fragment>
<fragment
android:id="@+id/product_detail"
android:name="com.example.android.persistence.ui.ProductDetailFragment"
android:label="Product Detail"
tools:layout="@layout/product_detail">
<argument
android:name="product_id"
app:argType="integer" />
</fragment>
</navigation>
Anschließend können Sie Ihre Aktivitäten aktualisieren:
Kotlin
class MainActivity : AppCompatActivity() { // No need to load the start destination, handled automatically by the Navigation component override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }
Java
public class MainActivity extends AppCompatActivity { // No need to load the start destination, handled automatically by the Navigation component @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
Für die Aktivität ist keine navigateToProductDetail()
-Methode mehr erforderlich. Im nächsten
Wir aktualisieren ProductListFragment
, um die NavController
zum Navigieren
zum nächsten Bildschirm
mit Produktdetails weitergeleitet.
Argumente sicher übergeben
Die Navigationskomponente verfügt über ein Gradle-Plug-in namens Sichere Argumente generiert einfache Objekt- und Builder-Klassen für typsicheren Zugriff auf für Ziele und Aktionen angegebene Argumente.
Nach der Anwendung des Plug-ins werden alle Argumente, die für ein Ziel in Ihrem
Navigationsdiagramm veranlasst, dass das Framework der Komponente "Navigation" ein
Die Klasse Arguments
, die typsichere Argumente für das Ziel bereitstellt.
Wenn Sie eine Aktion definieren, generiert das Plug-in eine Directions
-Konfiguration
Klasse, mit der dem NavController
mitgeteilt werden kann, wie der Nutzer zu
auf das Ziel hin. Wenn eine Aktion auf ein Ziel verweist, für das ein
enthält die generierte Directions
-Klasse Konstruktormethoden, die
die diese Parameter erfordern.
Verwenden Sie im Fragment NavController
und die generierte Directions
-Klasse, um
stellen typsichere Argumente für das Ziel bereit, wie im Folgenden gezeigt:
Beispiel:
Kotlin
class ProductListFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // In this example a callback is passed to respond to an item clicked in a RecyclerView productAdapter = ProductAdapter(productClickCallback) binding.productsList.setAdapter(productAdapter) } ... // The callback makes the call to the NavController to make the transition. private val productClickCallback = ProductClickCallback { product -> val directions = ProductListDirections.navigateToProductDetail(product.id) findNavController().navigate(directions) } }
Java
public class ProductListFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { // In this example a callback is passed to respond to an item clicked in a RecyclerView productAdapter = new ProductAdapter(productClickCallback); binding.productsList.setAdapter(productAdapter); } ... // The callback makes the call to the activity to make the transition. private ProductClickCallback productClickCallback = product -> { ProductListDirections.ViewProductDetails directions = ProductListDirections.navigateToProductDetail(product.getId()); NavHostFragment.findNavController(this).navigate(directions); }; }
Navigation der obersten Ebene
Wenn deine Anwendung ein DrawerLayout
verwendet, hast du möglicherweise umfangreiche Konfigurationslogik.
das Öffnen und Schließen der Leiste und das Navigieren
andere Ziele.
Die daraus resultierende Aktivität könnte etwa so aussehen:
Kotlin
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar: Toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolbar) val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout) val navView: NavigationView = findViewById(R.id.nav_view) val toggle = ActionBarDrawerToggle( this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close ) drawerLayout.addDrawerListener(toggle) toggle.syncState() navView.setNavigationItemSelectedListener(this) } override fun onBackPressed() { val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout) if (drawerLayout.isDrawerOpen(GravityCompat.START)) { drawerLayout.closeDrawer(GravityCompat.START) } else { super.onBackPressed() } } override fun onNavigationItemSelected(item: MenuItem): Boolean { // Handle navigation view item clicks here. when (item.itemId) { R.id.home -> { val homeFragment = HomeFragment() show(homeFragment) } R.id.gallery -> { val galleryFragment = GalleryFragment() show(galleryFragment) } R.id.slide_show -> { val slideShowFragment = SlideShowFragment() show(slideShowFragment) } R.id.tools -> { val toolsFragment = ToolsFragment() show(toolsFragment) } } val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout) drawerLayout.closeDrawer(GravityCompat.START) return true } } private fun show(fragment: Fragment) { val drawerLayout = drawer_layout as DrawerLayout val fragmentManager = supportFragmentManager fragmentManager .beginTransaction() .replace(R.id.main_content, fragment) .commit() drawerLayout.closeDrawer(GravityCompat.START) }
Java
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); DrawerLayout drawer = findViewById(R.id.drawer_layout); NavigationView navigationView = findViewById(R.id.nav_view); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.addDrawerListener(toggle); toggle.syncState(); navigationView.setNavigationItemSelectedListener(this); } @Override public void onBackPressed() { DrawerLayout drawer = findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } @Override public boolean onNavigationItemSelected(MenuItem item) { // Handle navigation view item clicks here. int id = item.getItemId(); if (id == R.id.home) { Fragment homeFragment = new HomeFragment(); show(homeFragment); } else if (id == R.id.gallery) { Fragment galleryFragment = new GalleryFragment(); show(galleryFragment); } else if (id == R.id.slide_show) { Fragment slideShowFragment = new SlideShowFragment(); show(slideShowFragment); } else if (id == R.id.tools) { Fragment toolsFragment = new ToolsFragment(); show(toolsFragment); } DrawerLayout drawer = findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); return true; } private void show(Fragment fragment) { DrawerLayout drawerLayout = findViewById(R.id.drawer_layout); FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager .beginTransaction() .replace(R.id.main_content, fragment) .commit(); drawerLayout.closeDrawer(GravityCompat.START); } }
Nachdem Sie die Navigationskomponente zu Ihrem Projekt hinzugefügt und eine
Navigationsdiagramm hinzugefügt haben, fügen Sie die einzelnen Inhaltsziele aus Ihrer Grafik hinzu (z. B.
Home (Startseite), Gallery (Galerie), SlideShow (Diashow) und Tools (Tools) aus dem obigen Beispiel. Achten Sie darauf,
die Werte deines Menüelements id
mit den zugehörigen id
-Werten für das Ziel übereinstimmen,
wie unten dargestellt:
<!-- activity_main_drawer.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="@+id/home"
android:icon="@drawable/ic_menu_camera"
android:title="@string/menu_home" />
<item
android:id="@+id/gallery"
android:icon="@drawable/ic_menu_gallery"
android:title="@string/menu_gallery" />
<item
android:id="@+id/slide_show"
android:icon="@drawable/ic_menu_slideshow"
android:title="@string/menu_slideshow" />
<item
android:id="@+id/tools"
android:icon="@drawable/ic_menu_manage"
android:title="@string/menu_tools" />
</group>
</menu>
<!-- activity_main_graph.xml -->
<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/main_graph"
app:startDestination="@id/home">
<fragment
android:id="@+id/home"
android:name="com.example.HomeFragment"
android:label="Home"
tools:layout="@layout/home" />
<fragment
android:id="@+id/gallery"
android:name="com.example.GalleryFragment"
android:label="Gallery"
tools:layout="@layout/gallery" />
<fragment
android:id="@+id/slide_show"
android:name="com.example.SlideShowFragment"
android:label="Slide Show"
tools:layout="@layout/slide_show" />
<fragment
android:id="@+id/tools"
android:name="com.example.ToolsFragment"
android:label="Tools"
tools:layout="@layout/tools" />
</navigation>
Wenn Sie die id
-Werte aus Ihrem Menü und der Grafik anpassen, können Sie die Werte verbinden.
NavController
für diese Aktivität, um die Navigation basierend auf
auf den Menüpunkt. NavController
übernimmt auch das Öffnen und Schließen des
DrawerLayout
und korrektes Verhalten der Schaltflächen „Aufwärts“ und „Zurück“.
Dein MainActivity
kann dann aktualisiert werden, um NavController
mit dem
Toolbar
und NavigationView
.
Das folgende Snippet zeigt ein Beispiel:
Kotlin
class MainActivity : AppCompatActivity() { val drawerLayout by lazy { findViewById<DrawerLayout>(R.id.drawer_layout) } val navController by lazy { (supportFragmentManager.findFragmentById(R.id.main_content) as NavHostFragment).navController } val navigationView by lazy { findViewById<NavigationView>(R.id.nav_view) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar = findViewById<Toolbar>(R.id.toolbar) setSupportActionBar(toolbar) // Show and Manage the Drawer and Back Icon setupActionBarWithNavController(navController, drawerLayout) // Handle Navigation item clicks // This works with no further action on your part if the menu and destination id’s match. navigationView.setupWithNavController(navController) } override fun onSupportNavigateUp(): Boolean { // Allows NavigationUI to support proper up navigation or the drawer layout // drawer menu, depending on the situation return navController.navigateUp(drawerLayout) } }
Java
public class MainActivity extends AppCompatActivity { private DrawerLayout drawerLayout; private NavController navController; private NavigationView navigationView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); drawerLayout = findViewById(R.id.drawer_layout); NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.main_content); navController = navHostFragment.getNavController(); navigationView = findViewById(R.id.nav_view); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); // Show and Manage the Drawer and Back Icon NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout); // Handle Navigation item clicks // This works with no further action on your part if the menu and destination id’s match. NavigationUI.setupWithNavController(navigationView, navController); } @Override public boolean onSupportNavigateUp() { // Allows NavigationUI to support proper up navigation or the drawer layout // drawer menu, depending on the situation. return NavigationUI.navigateUp(navController, drawerLayout); } }
Sie können das gleiche Verfahren mit der BottomNavigationView-basierten Navigation anwenden. und menübasierte Navigation. Weitere Informationen finden Sie unter UI-Komponenten mit NavigationUI aktualisieren finden Sie weitere Beispiele.
Aktivitätsziele hinzufügen
Sobald jeder Bildschirm in Ihrer App für die Nutzung der Navigationskomponente verbunden ist,
Sie verwenden FragmentTransactions
nicht mehr für den Wechsel zwischen
fragmentierten Zielen besteht der nächste Schritt darin, startActivity
Anrufe.
Identifizieren Sie zunächst die Stellen in Ihrer App, an denen zwei separate Navigationsgrafiken vorhanden sind.
und verwenden startActivity
für den Wechsel zwischen ihnen.
Dieses Beispiel enthält zwei Diagramme (A und B) und einen startActivity()
-Aufruf für
von A nach B zu wechseln.
Kotlin
fun navigateToProductDetails(productId: String) { val intent = Intent(this, ProductDetailsActivity::class.java) intent.putExtra(KEY_PRODUCT_ID, productId) startActivity(intent) }
Java
private void navigateToProductDetails(String productId) { Intent intent = new Intent(this, ProductDetailsActivity.class); intent.putExtra(KEY_PRODUCT_ID, productId); startActivity(intent);
Ersetzen Sie als Nächstes diese durch ein Aktivitätsziel in Diagramm A, das die die Navigation zur Hostaktivität in Diagramm B. Wenn Sie Argumente an die Startziel von Graph B, können Sie diese im Aktivitätsziel Definition.
Im folgenden Beispiel definiert Diagramm A ein Aktivitätsziel, das eine
product_id
-Argument zusammen mit einer Aktion. Grafik B enthält keine Änderungen.
Die XML-Darstellung der Grafiken A und B könnte wie folgt aussehen:
<!-- Graph A -->
<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/product_list_graph"
app:startDestination="@id/product_list">
<fragment
android:id="@+id/product_list"
android:name="com.example.android.persistence.ui.ProductListFragment"
android:label="Product List"
tools:layout="@layout/product_list_fragment">
<action
android:id="@+id/navigate_to_product_detail"
app:destination="@id/product_details_activity" />
</fragment>
<activity
android:id="@+id/product_details_activity"
android:name="com.example.android.persistence.ui.ProductDetailsActivity"
android:label="Product Details"
tools:layout="@layout/product_details_host">
<argument
android:name="product_id"
app:argType="integer" />
</activity>
</navigation>
<!-- Graph B -->
<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"
app:startDestination="@id/product_details">
<fragment
android:id="@+id/product_details"
android:name="com.example.android.persistence.ui.ProductDetailsFragment"
android:label="Product Details"
tools:layout="@layout/product_details_fragment">
<argument
android:name="product_id"
app:argType="integer" />
</fragment>
</navigation>
Zur Hostaktivität von Graph B gelangen Sie mit den Verwenden Sie zum Aufrufen von Fragmentzielen:
Kotlin
fun navigateToProductDetails(productId: String) { val directions = ProductListDirections.navigateToProductDetail(productId) findNavController().navigate(directions) }
Java
private void navigateToProductDetails(String productId) { ProductListDirections.NavigateToProductDetail directions = ProductListDirections.navigateToProductDetail(productId); Navigation.findNavController(getView()).navigate(directions);
Aktivitätszielargumente an ein Startzielfragment übergeben
Wenn die Zielaktivität wie im vorherigen Beispiel Extras erhält,
Sie können diese direkt als Argumente an das Startziel übergeben. Sie müssen jedoch
Navigationsdiagramm Ihres Hosts manuell in die
onCreate()
-Methode, sodass Sie die Intent-Extras als Argumente an die
wie unten dargestellt:
Kotlin
class ProductDetailsActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.product_details_host) val navHostFragment = supportFragmentManager.findFragmentById(R.id.main_content) as NavHostFragment val navController = navHostFramgent.navController navController .setGraph(R.navigation.product_detail_graph, intent.extras) } }
Java
public class ProductDetailsActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.product_details_host); NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.main_content); NavController navController = navHostFragment.getNavController(); navController .setGraph(R.navigation.product_detail_graph, getIntent().getExtras()); } }
Die Daten können mithilfe der MethodeBundle
generierte args-Klasse, wie im folgenden Beispiel gezeigt:
Kotlin
class ProductDetailsFragment : Fragment() { val args by navArgs<ProductDetailsArgs>() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val productId = args.productId ... } ...
Java
public class ProductDetailsFragment extends Fragment { ProductDetailsArgs args; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); args = ProductDetailsArgs.fromBundle(requireArguments()); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { int productId = args.getProductId(); ... } ...
Aktivitäten kombinieren
Sie können Navigationsdiagramme kombinieren, wenn mehrere Aktivitäten das gleiche
Layout zu erhalten, z. B. ein einfaches FrameLayout
mit einem einzelnen Fragment. In
In den meisten Fällen können Sie einfach alle Elemente aus den
Navigationsdiagramm und Aktualisierung aller Elemente des Aktivitätsziels zur Fragmentierung
Ziele.
Im folgenden Beispiel werden die Grafiken A und B aus dem vorherigen Abschnitt kombiniert:
Vor dem Kombinieren:
<!-- Graph A -->
<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/product_list_graph"
app:startDestination="@id/product_list">
<fragment
android:id="@+id/product_list"
android:name="com.example.android.persistence.ui.ProductListFragment"
android:label="Product List Fragment"
tools:layout="@layout/product_list">
<action
android:id="@+id/navigate_to_product_detail"
app:destination="@id/product_details_activity" />
</fragment>
<activity
android:id="@+id/product_details_activity"
android:name="com.example.android.persistence.ui.ProductDetailsActivity"
android:label="Product Details Host"
tools:layout="@layout/product_details_host">
<argument android:name="product_id"
app:argType="integer" />
</activity>
</navigation>
<!-- Graph B -->
<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/product_detail_graph"
app:startDestination="@id/product_details">
<fragment
android:id="@+id/product_details"
android:name="com.example.android.persistence.ui.ProductDetailsFragment"
android:label="Product Details"
tools:layout="@layout/product_details">
<argument
android:name="product_id"
app:argType="integer" />
</fragment>
</navigation>
Nach dem Kombinieren:
<!-- Combined Graph A and B -->
<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/product_list_graph"
app:startDestination="@id/product_list">
<fragment
android:id="@+id/product_list"
android:name="com.example.android.persistence.ui.ProductListFragment"
android:label="Product List Fragment"
tools:layout="@layout/product_list">
<action
android:id="@+id/navigate_to_product_detail"
app:destination="@id/product_details" />
</fragment>
<fragment
android:id="@+id/product_details"
android:name="com.example.android.persistence.ui.ProductDetailsFragment"
android:label="Product Details"
tools:layout="@layout/product_details">
<argument
android:name="product_id"
app:argType="integer" />
</fragment>
</navigation>
Wenn Sie die Aktionsnamen beibehalten, aber zusammenführen, ist das ein nahtloses Erlebnis.
und erfordert keine Änderungen an Ihrer vorhandenen Codebasis. Beispiel:
navigateToProductDetail
bleibt hier gleich. Der einzige Unterschied ist,
Diese Aktion stellt nun die Navigation zu einem Fragmentziel im selben
NavHost
statt eines Aktivitätsziels:
Kotlin
fun navigateToProductDetails(productId: String) { val directions = ProductListDirections.navigateToProductDetail(productId) findNavController().navigate(directions) }
Java
private void navigateToProductDetails(String productId) { ProductListDirections.NavigateToProductDetail directions = ProductListDirections.navigateToProductDetail(productId); Navigation.findNavController(getView()).navigate(directions);
Zusätzliche Ressourcen
Weitere Informationen zur Navigation finden Sie in den folgenden Themen:
- UI-Komponenten mit NavigationUI aktualisieren: Erfahren Sie, wie Sie die Navigation mit der oberen App-Leiste, der Navigationsleiste und Navigation am unteren Rand
- Navigation testen Informationen zum Testen von Navigations-Workflows für Ihre App