Navegação dobrável

O componente de navegação dobrável é uma biblioteca baseada na parte superior do componente de navegação do Android. Ele ajuda os desenvolvedores a implementar a navegação de fragmento em diferentes modos de tela ou adaptar um aplicativo existente ao padrão de Navegação Dobrável;

O componente de navegação dobrável consiste em três partes principais:

  • Grafo de navegação – um recurso XML que contém todas as informações relacionadas à navegação em uma localização centralizada. Ele é igual ao recurso do componente de navegação fornecido pelo Google.
  • FoldableNavHost – um contêiner vazio que exibe os destinos no seu grafo de navegação. A implementação da navegação dobrável é FoldableNavHostFragment.
  • FoldableNavController – um objeto que gerencia a navegação do aplicativo em um FoldableNavHost.

Visão geral

Os aplicativos em dispositivos dobráveis e de tela dupla podem ser exibidos em uma tela única ou estendidos em um recurso de dobra. Quando o aplicativo for iniciado pela primeira vez:

  • Na tela única, apenas um fragmento (A) ficará visível.
  • Se o aplicativo for renderizado em um recurso de dobra, o primeiro fragmento (A) estará no primeiro lado da dobra e o outro lado da dobra ficará em branco.

No estado inicial, se você navegar para outro fragmento (B), o novo fragmento será aberto na tela final.

Se o usuário navegar para um terceiro fragmento (C), ele será mostrado na tela final e o fragmento anterior (B) será movido na tela inicial.

  • Quando o aplicativo sair do modo estendido e passar para tela única, todos os fragmentos da tela final serão movidos para a tela inicial e (C) aparecerá na parte superior.
  • Quando o aplicativo passar de uma tela única para o modo estendido em uma dobra ou dobradiça, e a pilha de navegação tiver mais de dois fragmentos, o último fragmento será movido para a tela final.

Six different dual-screen examples demonstrating how fragments A, B, and C would appear after different navigation steps

Alterar o destino da área de exibição para ações

Você pode especificar onde um novo fragmento será exibido usando o atributo launchScreen no grafo de navegação. Os valores possíveis para launchScreen são:

  • start – o fragmento será aberto na primeira tela
  • end – o fragmento será aberto na segunda tela
  • both – o fragmento cobrirá toda a área de exibição

Este exemplo de XML de navegação mostra como usar este atributo:

<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/home"
    app:startDestination="@+id/titleScreen">

    <fragment
        android:id="@+id/titleScreen"
        android:name="com.microsoft.device.dualscreen.navigation.sample.homescreen.TitleFragment"
        android:label="@string/title_home"
        tools:layout="@layout/fragment_title">
        <action
            android:id="@+id/action_title_to_about"
            app:launchScreen="end"
            app:destination="@id/aboutScreen"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_right"
            app:popExitAnim="@anim/slide_out_left" />
    </fragment>
</navigation>

Importante

Esse atributo só pode ser alterado editando diretamente o arquivo XML. Ele não pode ser modificado usando o Editor do Android Studio.

Amostra

Você pode baixar este aplicativo de exemplo de navegação para ver todos esses comportamentos.

Como importar a biblioteca para seu projeto

  1. Adicione a dependência no arquivo build.gradle de nível de módulo:

    dependencies {
       def nav_version = "1.0.0-alpha3"
       implementation "com.microsoft.device.dualscreen:navigation-fragment-ktx:$nav_version"
       implementation "com.microsoft.device.dualscreen:navigation-ui-ktx:$nav_version"
    }
    

  1. Se seu projeto for criado usando Java, será preciso adicionar uma dependência kotlin-stdlib ao seu arquivo de nível de módulo build.gradle. (Isso ocorre porque alguma parte da biblioteca foi criada usando o Kotlin.)

    dependencies {
       implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    }
    

Esses componentes são criados com base no componente de navegação fornecido pelo Google e, portanto, a biblioteca de Navegação Dobrável contém uma dependência desse recurso.

Criar um grafo de navegação

Um grafo de navegação é um arquivo de recurso XML com todos os caminhos de navegação do seu aplicativo, usando destinos e ações. O grafo de navegação pode ser criado por meio do Editor de Navegação do Android Studio ou manualmente por meio de um editor de XML. Você pode encontrar mais informações em Criar um grafo de navegação.

Adicionar um NavHost a uma atividade

O componente de navegação dobrável é projetado para aplicativos com uma atividade principal e vários destinos de fragmento. A atividade principal é associada a um grafo de navegação e conterá um FoldableNavHostFragment responsável por trocar destinos de fragmento. Se o seu aplicativo tiver mais de uma atividade, cada atividade terá o próprio grafo de navegação.

Este é um exemplo de arquivo de layout XML da atividade principal, mostrando como definir o atributo app:navGraph:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/surface_duo_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.FoldableNavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

O FoldableNavHost também pode ser definido programaticamente:

val navHostFragment = FoldableNavHostFragment.create(navGraphId)
fragmentManager.beginTransaction()
    .add(containerId, navHostFragment, fragmentTag)
    .commitNow()

Você pode aprender mais sobre como adicionar o FoldableNavHost em Adicionar um NavHost em uma atividade.

Este snippet de código pode ser usado para navegar em fragmentos de acordo com as regras de navegação dobrável:

class SomeFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        view.findViewById<Button>(R.id.btn_next).setOnClickListener {
            findFoldableNavController().navigate(R.id.action_next)
        }
    }
}

Atualizar componentes da interface do usuário com FoldableNavigationUI

O FoldableNavigationUI é um componente semelhante ao NavigationUI no componente Jetpack Navigation e contém métodos estáticos que gerenciam a navegação com a barra de aplicativos superior, a gaveta de navegação e a navegação inferior. Você pode obter mais informações sobre

FoldableNavigationUI contém os seguintes métodos semelhantes aos fornecidos por NavigationUI:

// same method name, with foldable parameter
boolean onNavDestinationSelected(MenuItem item, FoldableNavController navController)
boolean navigateUp(FoldableNavController navController, Openable openableLayout)
boolean navigateUp(FoldableNavController navController, FoldableAppBarConfiguration configuration)
// method name changed to reflect foldable navigation
void setupActionBarWithFoldableNavController(AppCompatActivity activity, FoldableNavController navController)
void setupActionBarWithFoldableNavController(AppCompatActivity activity, FoldableNavController navController, Openable openableLayout)
void setupActionBarWithFoldableNavController(AppCompatActivity activity, FoldableNavController navController, FoldableAppBarConfiguration configuration)
void setupWithFoldableNavController(Toolbar toolbar, FoldableNavController navController)
void setupWithFoldableNavController(Toolbar toolbar, FoldableNavController navController, Openable openableLayout)
void setupWithFoldableNavController(Toolbar toolbar, FoldableNavController navController, FoldableAppBarConfiguration configuration)
void setupWithFoldableNavController(CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, FoldableNavController navController)
void setupWithFoldableNavController(CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, FoldableNavController navController, Openable openableLayout)
void setupWithFoldableNavController(CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, FoldableNavController navController, FoldableAppBarConfiguration configuration)
void setupWithFoldableNavController(NavigationView navigationView, FoldableNavController navController)
void setupWithFoldableNavController(BottomNavigationView bottomNavigationView, FoldableNavController navController)

Migrar aplicativos existentes para navegação dobrável

Os aplicativos existentes que usam o componente de navegação fornecido pelo Google podem adicionar a funcionalidade dobrável seguindo estas etapas:

  1. Use FoldableNavHostFragment em vez de NavHostFragment na exibição do contêiner de fragmentos alterando

    <androidx.fragment.app.FragmentContainerView
         android:id="@+id/nav_host_fragment"
         android:name="androidx.navigation.NavHostFragment"
    

    como

    <androidx.fragment.app.FragmentContainerView
         android:id="@+id/nav_host_fragment"
         android:name="androidx.navigation.FoldableNavHostFragment"
    
  2. Use findFoldableNavController para obter a instância de FoldableNavController e usá-la para navegar dentro do grafo de navegação alterando

    findNavController().navigate(R.id.action_next)
    

    como

    findFoldableNavController().navigate(R.id.action_next)
    
  3. Use FoldableNavigationUI em vez de NavigationUI alterando

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

    como

    val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as FoldableNavHostFragment
    val navController = navHostFragment.navController
    val appBarConfiguration = FoldableAppBarConfiguration(navController.graph)
    setupActionBarWithFoldableNavController(navController, appBarConfiguration)