Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cómo actualizar los componentes de IU con NavigationUI

El componente Navigation incluye una clase NavigationUI. Esta clase contiene métodos estáticos que administran la navegación con la barra superior de la app, el panel lateral de navegación y la navegación inferior.

Barra superior de la app

La barra superior de la app proporciona un lugar coherente en la parte superior de la app para mostrar información y acciones de la pantalla actual.

pantalla que muestra la barra superior de la app
Figura 1: Pantalla que muestra la barra superior de la app

La NavigationUI contiene métodos que actualizan automáticamente el contenido de la barra superior de la app a medida que los usuarios navegan por la app. Por ejemplo, NavigationUI usa las etiquetas de destino del gráfico de navegación para mantener actualizado el título de la barra superior de la app.

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

Cuando utilizas NavigationUI con las implementaciones de la barra superior de la app que se analizan a continuación, la etiqueta que adjuntas a los destinos se puede propagar automáticamente a partir de los argumentos proporcionados al destino mediante el formato de {argName} en tu etiqueta.

La NavigationUI proporciona compatibilidad con los siguientes tipos de barras superiores de la app:

Si deseas obtener más información sobre las barras de app, consulta Cómo configurar la barra de la app.

AppBarConfiguration

La NavigationUI usa un objeto AppBarConfiguration para administrar el comportamiento del botón Navigation en la esquina superior izquierda del área de visualización de tu app. El comportamiento del botón Navigation cambia si el usuario se encuentra en un destino de nivel superior.

Un destino de nivel superior es la raíz, o el destino de nivel más alto, en un conjunto de destinos relacionados de manera jerárquica. Los destinos de nivel superior no muestran un botón Arriba en la barra superior de la app, ya que no existe un destino superior a este. De forma predeterminada, el destino de inicio de la app es el único destino de nivel superior.

Cuando el usuario se encuentra en un destino de nivel superior, el botón Navigation se convierte en un ícono de panel lateral si el destino usa un DrawerLayout. Si el destino no usa un DrawerLayout, el botón Navigation está oculto. Cuando el usuario se encuentra en cualquier otro destino, el botón Navigation aparece como un botón Arriba . Si deseas configurar el botón Navigation solo con el destino de inicio como el destino de nivel superior, crea un objeto AppBarConfiguration y pasa el gráfico de navegación correspondiente, como se muestra a continuación:

Kotlin

val appBarConfiguration = AppBarConfiguration(navController.graph)

Java

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

En algunos casos, es posible que debas definir varios destinos de nivel superior en lugar de usar el destino de inicio predeterminado. Usar una BottomNavigationView es un caso de uso común en este contexto, donde puedes tener pantallas del mismo nivel que no están relacionadas entre sí de manera jerárquica y cada una puede tener su propio conjunto de destinos relacionados. En casos como estos, más bien puedes pasar un conjunto de ID de destino al constructor, como se muestra a continuación:

Kotlin

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

Java

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

Cómo crear una barra de herramientas

Si deseas crear una barra de herramientas con NavigationUI, primero define la barra en tu actividad principal, como se muestra a continuación:

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

Luego, llama a setupWithNavController() desde el método onCreate() de tu actividad principal, como se muestra en el siguiente ejemplo:

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);
}

Cómo incluir CollapsingToolbarLayout

Si deseas incluir un CollapsingToolbarLayout con tu barra de herramientas, primero define la barra de herramientas y el diseño circundante en tu actividad, como se muestra a continuación:

<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>

Luego, llama a setupWithNavController() desde el método onCreate de tu actividad principal, como se muestra a continuación:

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);
}

Barra de acciones

Si deseas agregar compatibilidad de navegación a la barra de acciones predeterminada, llama a setupActionBarWithNavController() desde el método onCreate() de tu actividad principal, como se muestra a continuación. Ten en cuenta que debes declarar tu AppBarConfiguration fuera de onCreate(), ya que también lo usarás cuando anules 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);
}

Luego, anula onSupportNavigateUp() para controlar la navegación hacia arriba:

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();
}

Compatibilidad con variantes de la barra de la app

Agregar la barra superior de la app a tu actividad funciona bien cuando el diseño de la barra de la app es similar para cada destino de tu app. Sin embargo, si la barra superior de la app cambia sutilmente entre los destinos, considera quitar la barra superior de la app de tu actividad y definirla en cada fragmento de destino.

Por ejemplo, uno de tus destinos puede usar una Toolbar estándar, mientras que otro usa un AppBarLayout para crear una barra de la app más compleja con pestañas, como se muestra en la figura 2.

dos variantes de la barra superior de la app; una Toolbar estándar a la izquierda y un AppBarLayout con una barra de herramientas y pestañas a la derecha
Figura 2: Dos variantes de la barra de la app. A la izquierda, una Toolbar estándar. A la derecha, un AppBarLayout con una Toolbar y pestañas.

Si deseas implementar este ejemplo en tus fragmentos de destino con NavigationUI, primero define la barra de la app en cada uno de los diseños de fragmentos y, luego, comienza con el fragmento de destino que usa una barra de herramientas estándar:

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

A continuación, define el fragmento de destino que usa una barra de la app con pestañas:

<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>

La lógica de configuración de la navegación es la misma para ambos fragmentos, excepto que debes llamar setupWithNavController() desde el método onViewCreated() de cada fragmento, en lugar de inicializarlos desde la actividad:

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);
}

Cómo vincular destinos a los elementos de menú

NavigationUI también proporciona asistentes para vincular destinos a componentes de IU controlados por el menú. NavigationUI contiene un método asistente, onNavDestinationSelected(), que toma un elemento MenuItem junto con el elemento NavController que aloja el destino asociado. Si el elemento id de MenuItem coincide con el elemento id del destino, NavController puede navegar a ese destino.

A modo de ejemplo, los siguientes fragmentos XML definen un elemento de menú y un destino con un id común, 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>

Si tu menú se agregó a través del onCreateOptionsMenu() de la actividad, por ejemplo, puedes asociar los elementos de menú con los destinos si anulas el parámetro onOptionsItemSelected() de la actividad para llamar a onNavDestinationSelected(), como se muestra en el siguiente ejemplo:

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);
}

Ahora, cuando un usuario haga clic en el elemento de menú details_page_fragment, la app navegará automáticamente al destino correspondiente con el mismo elemento id.

Cómo agregar un panel lateral de navegación

El panel lateral de navegación es un panel de IU que muestra el menú de navegación principal de tu app. El panel lateral aparece cuando el usuario toca el ícono del panel lateral en la barra de la app o cuando el usuario desliza un dedo desde el borde izquierdo de la pantalla.

un panel lateral abierto que muestra un menú de navegación
Figura 3: Panel lateral abierto que muestra un menú de navegación

El ícono del panel lateral se muestra en todos los destinos de nivel superior que usan un DrawerLayout.

Si deseas agregar un panel lateral de navegación, primero debes declarar un DrawerLayout como vista raíz. Dentro del DrawerLayout, agrega un diseño para el contenido principal de la IU y otra vista que tenga el contenido del panel lateral de navegación.

Por ejemplo, en el siguiente diseño, se utiliza un DrawerLayout con dos vistas secundarias: un NavHostFragment que abarca el contenido principal y un NavigationView para el contenido del panel lateral de navegación.

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

Luego, conecta el DrawerLayout a tu gráfico de navegación. Con ese fin, pásalo a AppBarConfiguration, como se muestra en el siguiente ejemplo:

Kotlin

val appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)

Java

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

Luego, en tu clase de actividad principal, llama a setupWithNavController() desde el método onCreate() de tu actividad principal, como se muestra a continuación:

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);
}

Navegación inferior

NavigationUI también puede controlar la navegación inferior. Cuando un usuario selecciona un elemento de menú, NavController llama a onNavDestinationSelected() y actualiza automáticamente el elemento seleccionado en la barra de navegación inferior.

barra de navegación inferior
Figura 4: Barra de navegación inferior

Si deseas crear una barra de navegación inferior en tu app, primero define la barra en tu actividad principal, como se muestra a continuación:

<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>

Luego, en tu clase de actividad principal, llama a setupWithNavController() desde el método onCreate() de tu actividad principal, como se muestra a continuación:

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);
}

Si deseas obtener un ejemplo completo que incluya la navegación inferior, consulta el Ejemplo de navegación avanzada de los componentes de la arquitectura de Android en GitHub.

Cómo detectar eventos de navegación

La interacción con NavController es el método principal para navegar entre destinos. El NavController es responsable de reemplazar el contenido de NavHost con el destino nuevo. En muchos casos, los elementos de la IU (por ejemplo, una barra superior de la app o los controles de navegación persistentes como BottomNavigationBar) permanecen fuera del NavHost y se deben actualizar a medida que navegas entre destinos.

El NavController ofrece una interfaz de OnDestinationChangedListener que se llama cuando el destino actual o los argumentos de NavController cambian. Es posible registrar un nuevo objeto de escucha mediante el método addOnDestinationChangedListener(). Ten en cuenta que, cuando se llama a addOnDestinationChangedListener(), si el destino actual existe, se envía de inmediato al objeto de escucha.

La NavigationUI usa OnDestinationChangedListener para hacer que estos componentes comunes de la IU reconozcan la navegación. Sin embargo, debes tener en cuenta que también puedes usar el elemento OnDestinationChangedListener solo con el fin de que cualquier IU personalizada o lógica de negocios esté al tanto de los eventos de navegación.

Por ejemplo, tal vez tengas elementos de IU comunes que quieras mostrar en algunas áreas de tu app y ocultar en otras. Con tu propio OnDestinationChangedListener, puedes ocultar o mostrar selectivamente estos elementos de la IU en función del destino objetivo, como se muestra en el siguiente ejemplo:

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);
       }
   }
});

Recursos adicionales

Si deseas obtener más información sobre la navegación, consulta los siguientes recursos adicionales.

Ejemplos

Codelabs

Entradas de blog

Videos