Łączenie komponentów interfejsu z kontrolerem NavController za pomocą interfejsu NavigationUI

Komponent Nawigacja zawiera klasę NavigationUI. Ta klasa zawiera metody statyczne zarządzające nawigacją za pomocą górnego paska aplikacji, panelu nawigacji i dolnego obszaru nawigacyjnego.

Górny pasek aplikacji

Pasek u góry aplikacji zapewnia spójne miejsce u góry, w którym wyświetlają się informacje i działania z bieżącego ekranu.

ekran z górnym paskiem aplikacji
Rysunek 1. Ekran z widocznym górnym paskiem aplikacji.

NavigationUI zawiera metody, które automatycznie aktualizują zawartość paska u góry aplikacji, gdy użytkownicy poruszają się po niej. Na przykład NavigationUI używa etykiet miejsc docelowych z wykresu nawigacyjnego, aby aktualizować tytuł górnego paska aplikacji.

<navigation>
    <fragment ...
              android:label="Page title">
      ...
    </fragment>
</navigation>

Jeśli używasz funkcji NavigationUI z omówionymi poniżej najpopularniejszymi implementacjami paska aplikacji, etykieta dołączana do miejsc docelowych może zostać automatycznie wypełniona na podstawie argumentów podanych w miejscu docelowym za pomocą formatu {argName} w etykiecie.

NavigationUI zapewnia obsługę tych najpopularniejszych typów pasków aplikacji:

Więcej informacji o paskach aplikacji znajdziesz w artykule Konfigurowanie paska aplikacji.

Konfiguracja paska aplikacji

NavigationUI używa obiektu AppBarConfiguration do zarządzania działaniem przycisku nawigacji w lewym górnym rogu obszaru wyświetlania aplikacji. Sposób działania przycisku nawigacyjnego zależy od tego, czy użytkownik znajduje się w miejscu docelowym najwyższego poziomu.

Miejsce docelowe najwyższego poziomu to miejsce docelowe najwyższego poziomu w zestawie powiązanych hierarchicznie miejsc docelowych. W przypadku miejsc docelowych najwyższego poziomu na górnym pasku aplikacji nie ma przycisku W górę, ponieważ nie ma tu wyższego poziomu. Domyślnie początkowym miejscem docelowym aplikacji jest jej jedyny punkt docelowy najwyższego poziomu.

Gdy użytkownik znajduje się w miejscu docelowym najwyższego poziomu, przycisk nawigacji staje się ikoną szuflady , jeśli w miejscu docelowym jest używany element DrawerLayout. Jeśli miejsce docelowe nie korzysta z elementu DrawerLayout, przycisk nawigacji jest ukryty. Gdy użytkownik znajduje się w innym miejscu docelowym, przycisk nawigacji ma postać przycisku W górę . Aby skonfigurować przycisk nawigacji, używając tylko początkowego miejsca docelowego jako miejsca docelowego najwyższego poziomu, utwórz obiekt AppBarConfiguration i przekaż go na odpowiedni wykres nawigacyjny, jak pokazano poniżej:

Kotlin

val appBarConfiguration = AppBarConfiguration(navController.graph)

Java

AppBarConfiguration appBarConfiguration =
        new AppBarConfiguration.Builder(navController.getGraph()).build();

W niektórych przypadkach może być konieczne zdefiniowanie wielu miejsc docelowych najwyższego poziomu zamiast używania domyślnego miejsca docelowego początkowego. Częstym przypadkiem użycia jest użycie elementu BottomNavigationView, w którym możesz mieć ekrany równorzędne, które nie są ze sobą powiązane hierarchicznie i mogą mieć własny zestaw powiązanych miejsc docelowych. W takich przypadkach możesz zamiast tego przekazać do konstruktora zestaw identyfikatorów miejsc docelowych w ten sposób:

Kotlin

val appBarConfiguration = AppBarConfiguration(setOf(R.id.main, R.id.profile))

Java

AppBarConfiguration appBarConfiguration =
        new AppBarConfiguration.Builder(R.id.main, R.id.profile).build();

Utwórz pasek narzędzi

Aby utworzyć pasek narzędzi z elementem NavigationUI, najpierw zdefiniuj pasek w głównej aktywności, tak jak poniżej:

<LinearLayout>
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar" />
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        ... />
    ...
</LinearLayout>

Następnie wywołaj setupWithNavController() z metody onCreate() głównej aktywności, jak w tym przykładzie:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    setContentView(R.layout.activity_main)

    ...

    val navController = findNavController(R.id.nav_host_fragment)
    val appBarConfiguration = AppBarConfiguration(navController.graph)
    findViewById<Toolbar>(R.id.toolbar)
        .setupWithNavController(navController, appBarConfiguration)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_main);

    ...

    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    AppBarConfiguration appBarConfiguration =
            new AppBarConfiguration.Builder(navController.getGraph()).build();
    Toolbar toolbar = findViewById(R.id.toolbar);
    NavigationUI.setupWithNavController(
            toolbar, navController, appBarConfiguration);
}

Aby skonfigurować wyświetlanie przycisku nawigacji jako przycisku W górę w przypadku wszystkich miejsc docelowych, podczas tworzenia obiektu AppBarConfiguration przekaż pusty zestaw identyfikatorów miejsc docelowych najwyższego poziomu. Może to być przydatne, jeśli na przykład masz drugą aktywność, w przypadku której w Toolbar we wszystkich miejscach docelowych powinien być wyświetlany przycisk w górę. Dzięki temu użytkownik może wrócić do aktywności nadrzędnej, gdy w tylnym stosie nie ma żadnych innych miejsc docelowych. Za pomocą właściwości setFallbackOnNavigateUpListener() możesz kontrolować działanie kreacji zastępczej w sytuacji, gdy navigateUp() w przeciwnym razie nic nie robi, jak w tym przykładzie:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    val appBarConfiguration = AppBarConfiguration(
        topLevelDestinationIds = setOf(),
        fallbackOnNavigateUpListener = ::onSupportNavigateUp
    )
    findViewById<Toolbar>(R.id.toolbar)
        .setupWithNavController(navController, appBarConfiguration)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    NavHostFragment navHostFragment = (NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder()
        .setFallbackOnNavigateUpListener(::onSupportNavigateUp)
        .build();
    Toolbar toolbar = findViewById(R.id.toolbar);
    NavigationUI.setupWithNavController(
            toolbar, navController, appBarConfiguration);
}

Uwzględnij układ zwijanego paska narzędzi

Aby dołączyć CollapsingToolbarLayout do paska narzędzi, najpierw zdefiniuj pasek narzędzi i jego układ w aktywności, jak pokazano poniżej:

<LinearLayout>
    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/tall_toolbar_height">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleGravity="top"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"/>
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        ... />
    ...
</LinearLayout>

Następnie wywołaj setupWithNavController() z metody onCreate głównej aktywności, jak pokazano poniżej:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    setContentView(R.layout.activity_main)

    ...

    val layout = findViewById<CollapsingToolbarLayout>(R.id.collapsing_toolbar_layout)
    val toolbar = findViewById<Toolbar>(R.id.toolbar)
    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    val appBarConfiguration = AppBarConfiguration(navController.graph)
    layout.setupWithNavController(toolbar, navController, appBarConfiguration)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_main);

    ...

    CollapsingToolbarLayout layout = findViewById(R.id.collapsing_toolbar_layout);
    Toolbar toolbar = findViewById(R.id.toolbar);
    NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    AppBarConfiguration appBarConfiguration =
            new AppBarConfiguration.Builder(navController.getGraph()).build();
    NavigationUI.setupWithNavController(layout, toolbar, navController, appBarConfiguration);
}

Pasek działań

Aby dodać obsługę nawigacji do domyślnego paska działań, wywołaj metodę setupActionBarWithNavController() z metody onCreate() głównej aktywności, jak pokazano poniżej. Pamiętaj, że musisz zadeklarować AppBarConfiguration poza domeną onCreate(), ponieważ używasz jej też podczas zastępowania onSupportNavigateUp():

Kotlin

private lateinit var appBarConfiguration: AppBarConfiguration

...

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    appBarConfiguration = AppBarConfiguration(navController.graph)
    setupActionBarWithNavController(navController, appBarConfiguration)
}

Java

AppBarConfiguration appBarConfiguration;

...

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
    NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
}

Następnie zastąp onSupportNavigateUp(), aby obsługiwać nawigację w górę:

Kotlin

override fun onSupportNavigateUp(): Boolean {
    val navController = findNavController(R.id.nav_host_fragment)
    return navController.navigateUp(appBarConfiguration)
            || super.onSupportNavigateUp()
}

Java

@Override
public boolean onSupportNavigateUp() {
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    return NavigationUI.navigateUp(navController, appBarConfiguration)
            || super.onSupportNavigateUp();
}

Obsługuj odmiany paska aplikacji

Dodanie górnego paska aplikacji do aktywności sprawdza się, gdy układ paska aplikacji jest podobny w przypadku każdego miejsca docelowego w aplikacji. Jeśli jednak górny pasek aplikacji zmienia się istotnie w różnych miejscach docelowych, zastanów się nad usunięciem górnego paska aplikacji z aktywności i zdefiniowaniem go w poszczególnych fragmentach docelowych.

Na przykład jedno z Twoich miejsc docelowych może używać standardowego paska Toolbar, a w drugim – AppBarLayout do utworzenia bardziej złożonego paska aplikacji z kartami, jak widać na rysunku 2.

2 najpopularniejsze odmiany paska aplikacji: standardowy pasek narzędzi po lewej stronie i układ aplikacji z paskiem narzędzi i kartami po prawej stronie
Rysunek 2. Dwie wersje paska aplikacji. Po lewej stronie Toolbar. Po prawej stronie obszar AppBarLayout z elementem Toolbar i kartami.

Aby zaimplementować ten przykład we fragmentach docelowych za pomocą parametru NavigationUI, najpierw zdefiniuj pasek aplikacji w każdym układzie fragmentów, zaczynając od fragmentu docelowego, który korzysta ze standardowego paska narzędzi:

<LinearLayout>
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        ... />
    ...
</LinearLayout>

Następnie określ fragment docelowy, który używa paska aplikacji z kartami:

<LinearLayout>
    <com.google.android.material.appbar.AppBarLayout
        ... />

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            ... />

        <com.google.android.material.tabs.TabLayout
            ... />

    </com.google.android.material.appbar.AppBarLayout>
    ...
</LinearLayout>

Logika konfiguracji nawigacji jest taka sama w przypadku obu tych fragmentów, z tą różnicą, że należy wywoływać metodę setupWithNavController() z metody onViewCreated() każdego fragmentu zamiast inicjowania go z poziomu aktywności:

Kotlin

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val navController = findNavController()
    val appBarConfiguration = AppBarConfiguration(navController.graph)

    view.findViewById<Toolbar>(R.id.toolbar)
            .setupWithNavController(navController, appBarConfiguration)
}

Java

@Override
public void onViewCreated(@NonNull View view,
                          @Nullable Bundle savedInstanceState) {
    NavController navController = Navigation.findNavController(view);
    AppBarConfiguration appBarConfiguration =
            new AppBarConfiguration.Builder(navController.getGraph()).build();
    Toolbar toolbar = view.findViewById(R.id.toolbar);

    NavigationUI.setupWithNavController(
            toolbar, navController, appBarConfiguration);
}

Powiąż miejsca docelowe z pozycjami menu

NavigationUI udostępnia też elementy pomocnicze do łączenia miejsc docelowych z komponentami interfejsu opartymi na menu. NavigationUI zawiera metodę pomocniczą onNavDestinationSelected(), która wymaga metody MenuItem wraz z NavController hostującym powiązane miejsce docelowe. Jeśli id MenuItem odpowiada id miejsca docelowego, NavController może wyświetlić wskazówki dojazdu do tego miejsca docelowego.

Na przykład podane niżej fragmenty kodu XML definiują pozycję menu i miejsce docelowe o typowym elemencie id (details_page_fragment):

<?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"
    ... >

    ...

    <fragment android:id="@+id/details_page_fragment"
         android:label="@string/details"
         android:name="com.example.android.myapp.DetailsFragment" />
</navigation>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    ...

    <item
        android:id="@+id/details_page_fragment"
        android:icon="@drawable/ic_details"
        android:title="@string/details" />
</menu>

Jeśli menu zostało dodane na przykład za pomocą elementu onCreateOptionsMenu() aktywności, możesz go powiązać z miejscami docelowymi, zastępując element onOptionsItemSelected() aktywności, aby wywołać onNavDestinationSelected(), jak w tym przykładzie:

Kotlin

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    val navController = findNavController(R.id.nav_host_fragment)
    return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
}

Java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    return NavigationUI.onNavDestinationSelected(item, navController)
            || super.onOptionsItemSelected(item);
}

Teraz, gdy użytkownik kliknie menu details_page_fragment, aplikacja automatycznie przejdzie do odpowiedniego miejsca docelowego z tym samym atrybutem id.

Dodaj panel nawigacji

Panel nawigacji to panel interfejsu, w którym widać główne menu nawigacyjne aplikacji. Panel wyświetla się, gdy użytkownik dotknie ikony panelu aplikacji na pasku aplikacji lub przesunie palcem od lewej krawędzi ekranu.

otwarty panel z menu nawigacyjnym
Rysunek 3. Otwarty panel z menu nawigacyjnym.

Ikona szuflady wyświetla się we wszystkich miejscach docelowych najwyższego poziomu, które używają DrawerLayout.

Aby dodać panel nawigacji, najpierw zadeklaruj DrawerLayout jako widok główny. W DrawerLayout dodaj układ dla głównej zawartości interfejsu oraz kolejny widok, który zawiera zawartość szuflady nawigacji.

Na przykład w tym układzie wykorzystano obiekt DrawerLayout z 2 widokami podrzędnymi: NavHostFragment do wyświetlania głównej treści i NavigationView do zawartości panelu nawigacji.

<?xml version="1.0" encoding="utf-8"?>
<!-- Use DrawerLayout as root container for activity -->
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <!-- Layout to contain contents of main body of screen (drawer will slide over this) -->
    <androidx.fragment.app.FragmentContainerView
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:id="@+id/nav_host_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

    <!-- Container for contents of drawer - use NavigationView to make configuration easier -->
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true" />

</androidx.drawerlayout.widget.DrawerLayout>

Następnie połącz obiekt DrawerLayout z wykresem nawigacyjnym, przekazując go do interfejsu AppBarConfiguration, jak pokazano w tym przykładzie:

Kotlin

val appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)

Java

AppBarConfiguration appBarConfiguration =
        new AppBarConfiguration.Builder(navController.getGraph())
            .setDrawerLayout(drawerLayout)
            .build();

Następnie w głównej klasie aktywności wywołaj metodę setupWithNavController() z metody onCreate() głównej aktywności, jak pokazano poniżej:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    setContentView(R.layout.activity_main)

    ...

    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    findViewById<NavigationView>(R.id.nav_view)
        .setupWithNavController(navController)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_main);

    ...

    NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    NavigationView navView = findViewById(R.id.nav_view);
    NavigationUI.setupWithNavController(navView, navController);
}

Od Nawigacji 2.4.0-alpha01 stan każdej pozycji menu jest zapisywany i przywracany, gdy użyjesz funkcji setupWithNavController.

Dolna nawigacja

NavigationUI może też obsługiwać nawigację u dołu. Gdy użytkownik wybiera pozycję menu, NavController wywołuje metodę onNavDestinationSelected() i automatycznie aktualizuje wybraną pozycję na dolnym pasku nawigacyjnym.

dolny pasek nawigacyjny
Rysunek 4. Dolny pasek nawigacyjny.

Aby utworzyć dolny pasek nawigacyjny w aplikacji, najpierw zdefiniuj pasek w głównej aktywności, jak pokazano poniżej:

<LinearLayout>
    ...
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        ... />
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav"
        app:menu="@menu/menu_bottom_nav" />
</LinearLayout>

Następnie w głównej klasie aktywności wywołaj metodę setupWithNavController() z metody onCreate() głównej aktywności, jak pokazano poniżej:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    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) {
    setContentView(R.layout.activity_main);

    ...

    NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);
    NavigationUI.setupWithNavController(bottomNav, navController);
}

Od Nawigacji 2.4.0-alpha01 stan każdej pozycji menu jest zapisywany i przywracany, gdy użyjesz funkcji setupWithNavController.

Wszechstronny przykład z dolnym menu nawigacyjnym znajdziesz w przykładzie zaawansowanej nawigacji w architekturze Android na GitHubie.

Wykrywaj zdarzenia nawigacji

Korzystanie z elementu NavController to główna metoda poruszania się między miejscami docelowymi. NavController odpowiada za zastąpienie zawartości NavHost nowym miejscem docelowym. W wielu przypadkach elementy interfejsu – takie jak górny pasek aplikacji czy inne trwałe elementy sterujące nawigacji (np. BottomNavigationBar) – działają poza NavHost i wymagają aktualizacji w miarę nawigowania między miejscami docelowymi.

NavController oferuje interfejs OnDestinationChangedListener, który jest wywoływany w przypadku zmiany bieżącego miejsca docelowego lub jego argumentów na urządzeniu NavController. Nowy detektor można zarejestrować za pomocą metody addOnDestinationChangedListener(). Pamiętaj, że gdy wywołujesz addOnDestinationChangedListener(), jeśli obecne miejsce docelowe istnieje, jest natychmiast wysyłane do odbiornika.

NavigationUI korzysta z OnDestinationChangedListener, aby te typowe komponenty UI informowały o nawigacji. Pamiętaj jednak, że możesz też używać właściwości OnDestinationChangedListener, aby każdy niestandardowy interfejs użytkownika lub logika biznesowa uwzględniała zdarzenia nawigacji.

Możesz na przykład mieć wspólne elementy interfejsu, które zamierzasz wyświetlać w niektórych obszarach aplikacji, a ukrywać je w innych. Korzystając z własnego elementu OnDestinationChangedListener, możesz selektywnie wyświetlać lub ukrywać te elementy interfejsu w zależności od miejsca docelowego, jak w tym przykładzie:

Kotlin

navController.addOnDestinationChangedListener { _, destination, _ ->
   if(destination.id == R.id.full_screen_destination) {
       toolbar.visibility = View.GONE
       bottomNavigationView.visibility = View.GONE
   } else {
       toolbar.visibility = View.VISIBLE
       bottomNavigationView.visibility = View.VISIBLE
   }
}

Java

navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
   @Override
   public void onDestinationChanged(@NonNull NavController controller,
           @NonNull NavDestination destination, @Nullable Bundle arguments) {
       if(destination.getId() == R.id.full_screen_destination) {
           toolbar.setVisibility(View.GONE);
           bottomNavigationView.setVisibility(View.GONE);
       } else {
           toolbar.setVisibility(View.VISIBLE);
           bottomNavigationView.setVisibility(View.VISIBLE);
       }
   }
});

Detektory oparte na argumentach

Zamiast tego możesz też na wykresie nawigacyjnym używać argumentów z wartościami domyślnymi, których może użyć odpowiedni kontroler interfejsu, by zaktualizować jego stan. Na przykład zamiast oprzeć logikę w elemencie OnDestinationChangedListener na identyfikatorze miejsca docelowego tak jak w poprzednim przykładzie, możemy utworzyć argument w elemencie NavGraph:

<?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"
    android:id="@+id/navigation\_graph"
    app:startDestination="@id/fragmentOne">
    <fragment
        android:id="@+id/fragmentOne"
        android:name="com.example.android.navigation.FragmentOne"
        android:label="FragmentOne">
        <action
            android:id="@+id/action\_fragmentOne\_to\_fragmentTwo"
            app:destination="@id/fragmentTwo" />
    </fragment>
    <fragment
        android:id="@+id/fragmentTwo"
        android:name="com.example.android.navigation.FragmentTwo"
        android:label="FragmentTwo">
        <argument
            android:name="ShowAppBar"
            android:defaultValue="true" />
    </fragment>
</navigation>

Ten argument nie jest używany podczas nawigacji do miejsca docelowego, ale nie stanowi sposobu na dołączenie do miejsca docelowego dodatkowych informacji za pomocą właściwości defaultValue. W tym przypadku wartość wskazuje, czy pasek aplikacji powinien być wyświetlany w tym miejscu docelowym.

Możemy teraz dodać obiekt OnDestinationChangedListener w Activity:

Kotlin

navController.addOnDestinationChangedListener { _, _, arguments ->
    appBar.isVisible = arguments?.getBoolean("ShowAppBar", false) == true
}

Java

navController.addOnDestinationChangedListener(
        new NavController.OnDestinationChangedListener() {
            @Override
            public void onDestinationChanged(
                    @NonNull NavController controller,
                    @NonNull NavDestination destination,
                    @Nullable Bundle arguments
            ) {
                boolean showAppBar = false;
                if (arguments != null) {
                    showAppBar = arguments.getBoolean("ShowAppBar", false);
                }
                if(showAppBar) {
                    appBar.setVisibility(View.VISIBLE);
                } else {
                    appBar.setVisibility(View.GONE);
                }
            }
        }
);

NavController wywołuje to wywołanie zwrotne przy każdej zmianie miejsca docelowego nawigacji. Activity może teraz aktualizować stan lub widoczność swoich komponentów UI na podstawie argumentów otrzymanych w wywołaniu zwrotnym.

Jedną z zalet tego podejścia jest to, że Activity widzi tylko argumenty na wykresie nawigacyjnym i nie zna poszczególnych ról Fragment ani ich odpowiedzialności. Podobnie poszczególne fragmenty nie wiedzą o elemencie Activity ani o należących do niego komponentach interfejsu.

Dodatkowe materiały

Więcej informacji o nawigacji znajdziesz w tych materiałach dodatkowych.

Próbki

Ćwiczenia z programowania

Posty na blogu

Filmy