Projetar o gráfico de navegação

O componente Navigation usa um gráfico de navegação para gerenciar a navegação do seu app. O gráfico de navegação é uma estrutura de dados que contém cada destino no app e as conexões entre eles.

Tipos de destino

Existem três tipos gerais de destinos: hospedado, caixa de diálogo e atividade. A tabela abaixo descreve esses três tipos de destino e as finalidades deles.

Tipo

Descrição

Casos de uso

Hospedado

Preenche todo o host de navegação. Ou seja, o tamanho de um destino hospedado é o mesmo do host de navegação, e os destinos anteriores não são visíveis.

Telas principal e de detalhes.

Caixa de diálogo

Apresenta componentes de interface de sobreposição. Essa interface não está vinculada ao local nem ao tamanho do host de navegação. Os destinos anteriores ficam visíveis abaixo dele.

Alertas, seleções, formulários.

Atividade

Representa telas ou recursos únicos no app.

Serve como um ponto de saída para o gráfico de navegação que inicia uma nova atividade do Android gerenciada separadamente do componente Navigation.

No Modern Android Development, um app consiste em uma única atividade. Os destinos de atividade são mais indicados para interagir com atividades de terceiros ou como parte do processo de migração.

Este documento contém exemplos de destinos hospedados, que são os destinos mais comuns e fundamentais. Consulte os guias abaixo para mais informações sobre outros destinos:

Estruturas de trabalho

Embora o mesmo fluxo de trabalho geral se aplique a todos os casos, a maneira exata de criar um host e um gráfico de navegação depende do framework da interface que você usa.

  • Compose: use o elemento combinável NavHost. Adicione um NavGraph a ela usando o DSL do Kotlin (link em inglês). É possível criar o gráfico de duas maneiras:
    • Como parte do NavHost: construa o gráfico de navegação diretamente como parte da adição do NavHost.
    • De forma programática: use o método NavController.createGraph() para criar um NavGraph e transmiti-lo diretamente para o NavHost.
  • Fragmentos:ao usar fragmentos com o framework de interface de visualizações, use um NavHostFragment como host. Há várias maneiras de criar uma navegação gráfico:
    • De forma programática:use a DSL do Kotlin para criar um NavGraph e aplicá-lo diretamente no NavHostFragment.
      • A função createGraph() usada com a DSL do Kotlin para ambos fragmentos e o Compose é o mesmo.
    • XML: programe o host e o gráfico de navegação diretamente em XML.
    • Editor do Android Studio: use o editor de GUI no Android Studio para criar e ajustar o gráfico como um arquivo de recurso XML.

Escrever

No Compose, use um objeto ou uma classe serializável para definir uma rota. Trajeto A descreve como chegar a um destino e contém todas as informações que o o destino exige. Depois de definir suas rotas, use o NavHost para criar seu gráfico de navegação. Veja o exemplo a seguir:

@Serializable
object Profile
@Serializable
object FriendsList

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
    // Add more destinations similarly.
}
  1. Um objeto serializável representa cada uma das duas rotas, Profile e FriendsList.
  2. A chamada para o elemento combinável NavHost transmite um NavController e uma rota. para o destino inicial.
  3. A lambda transmitida ao NavHost chama NavController.createGraph() e retorna um NavGraph.
  4. Cada rota é fornecida como um argumento de tipo para NavGraphBuilder.composable<T>(), que adiciona o destino ao NavGraph resultante.
  5. A lambda transmitida ao composable é o que o NavHost mostra para isso destino.
.

Entender o lambda

Para entender melhor a lambda que cria o NavGraph, considere que, para criar o mesmo gráfico do snippet anterior, você poderia criar o NavGraph separadamente usando NavController.createGraph() e transmitindo diretamente para o NavHost:

val navGraph by remember(navController) {
  navController.createGraph(startDestination = Profile)) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
  }
}
NavHost(navController, navGraph)

Transmitir argumentos

Se você precisar transmitir dados para um destino, defina a rota com uma classe que tem parâmetros. Por exemplo, a rota Profile é uma classe de dados com um name .

@Serializable
data class Profile(val name: String)

Sempre que precisar transmitir argumentos para esse destino, crie uma instância da sua classe de rota, passando os argumentos para o construtor da classe.

Para argumentos opcionais, crie campos anuláveis com um valor padrão.

@Serializable
data class Profile(val nickname: String? = null)

Acessar instância da rota

Você pode conseguir a instância da rota com NavBackStackEntry.toRoute() ou SavedStateHandle.toRoute(). Quando você cria um destino usando composable(), o NavBackStackEntry estará disponível como um parâmetro.

@Serializable
data class Profile(val name: String)

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile(name="John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(name = profile.name) }
}

Observe o seguinte nesse snippet:

  • A rota Profile especifica o destino inicial na navegação. gráfico, com "John Smith" como argumento para name.
  • O destino em si é o bloco composable<Profile>{}.
  • O elemento combinável ProfileScreen usa o valor de profile.name por conta própria argumento name.
  • Dessa forma, o valor "John Smith" é transmitido para ProfileScreen.

Exemplo mínimo

Um exemplo completo de NavController e NavHost trabalhando juntos:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Define the ProfileScreen composable.
@Composable
fun ProfileScreen(
    profile: Profile
    onNavigateToFriendsList: () -> Unit,
  ) {
  Text("Profile for ${profile.name}")
  Button(onClick = { onNavigateToFriendsList() }) {
    Text("Go to Friends List")
  }
}

// Define the FriendsListScreen composable.
@Composable
fun FriendsListScreen(onNavigateToProfile: () -> Unit) {
  Text("Friends List")
  Button(onClick = { onNavigateToProfile() }) {
    Text("Go to Profile")
  }
}

// Define the MyApp composable, including the `NavController` and `NavHost`.
@Composable
fun MyApp() {
  val navController = rememberNavController()
  NavHost(navController, startDestination = Profile(name = "John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(
            profile = profile,
            onNavigateToFriendsList = {
                navController.navigate(route = FriendsList)
            }
        )
    }
    composable<FriendsList> {
      FriendsListScreen(
        onNavigateToProfile = {
          navController.navigate(
            route = Profile(name = "Aisha Devi")
          )
        }
      )
    }
  }
}

Como demonstrado no snippet, em vez de transmitir o NavController para os elementos combináveis, exponha um evento para o NavHost. Ou seja, os elementos combináveis precisam ter um parâmetro do tipo () -> Unit para o qual o NavHost transmite uma lambda que chama NavController.navigate().

Fragmentos

Conforme descrito nas seções anteriores, ao usar fragmentos, você tem a opção de criar um gráfico de navegação de forma programática usando a DSL do Kotlin, o XML ou o editor do Android Studio.

As seções abaixo detalham essas diferentes abordagens.

De forma programática

A DSL do Kotlin oferece uma maneira programática de criar um gráfico de navegação com fragmentos. Isso acaba ficando mais bem organizado e moderno do que usar um arquivo de recurso XML.

Confira o exemplo abaixo, que implementa um gráfico de navegação em duas telas.

Primeiro, é necessário criar o NavHostFragment, que não pode incluir um elemento app:navGraph:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

Em seguida, transmita o id do NavHostFragment para NavController.findNavController. Isso associa o NavController o NavHostFragment.

Em seguida, a chamada para NavController.createGraph() vincula o gráfico o NavController e, consequentemente, também o NavHostFragment:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Retrieve the NavController.
val navController = findNavController(R.id.nav_host_fragment)

// Add the graph to the NavController with `createGraph()`.
navController.graph = navController.createGraph(
    startDestination = Profile(name = "John Smith")
) {
    // Associate each destination with one of the route constants.
    fragment<ProfileFragment, Profile> {
        label = "Profile"
    }

    fragment<FriendsListFragment, FriendsList>() {
        label = "Friends List"
    }

    // Add other fragment destinations similarly.
}

O uso da DSL dessa maneira é muito semelhante ao fluxo de trabalho descrito na seção anterior no Compose. Por exemplo, lá e aqui, a função NavController.createGraph() gera o NavGraph. Da mesma forma, enquanto NavGraphBuilder.composable() adiciona destinos combináveis ao gráfico, aqui NavGraphBuilder.fragment() adiciona um destino de fragmento.

Para saber mais sobre como usar a DSL do Kotlin, consulte Criar um gráfico com a DSL do NavGraphBuilder.

XML

Você pode criar o XML diretamente. O exemplo abaixo espelha e é equivalente ao exemplo de duas telas da seção anterior.

Primeiro, crie um NavHostFragment. Ele serve como o host de navegação, que contém o gráfico de navegação real.

Uma implementação mínima de um NavHostFragment:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navGraph="@navigation/nav_graph" />

</FrameLayout>

O NavHostFragment contém o atributo app:navGraph. Use este atributo para conectar o gráfico ao host de navegação. Confira abaixo um exemplo de como implementar o gráfico:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/profile">

    <fragment
        android:id="@+id/profile"
        android:name="com.example.ProfileFragment"
        android:label="Profile">

        <!-- Action to navigate from Profile to Friends List. -->
        <action
            android:id="@+id/action_profile_to_friendslist"
            app:destination="@id/friendslist" />
    </fragment>

    <fragment
        android:id="@+id/friendslist"
        android:name="com.example.FriendsListFragment"
        android:label="Friends List" />

    <!-- Add other fragment destinations similarly. -->
</navigation>

Você usa ações para definir as conexões entre destinos diferentes. Neste exemplo, o fragmento profile contém uma ação que navega para friendslist. Para saber mais, consulte Usar ações e fragmentos de navegação.

Editor

Você pode gerenciar o gráfico de navegação do seu app usando o Navigation Editor no Android Studio. Essencialmente, essa é uma GUI que pode ser usada para criar e editar o XML do NavigationFragment, conforme mostrado na seção anterior.

Para mais informações, consulte o Navigation Editor.

Gráficos aninhados

Também é possível usar gráficos aninhados. Isso envolve o uso de um gráfico como destino de navegação. Para mais informações, consulte Gráficos aninhados.

Leia mais

Para conferir mais dos principais conceitos de navegação, consulte os guias abaixo: