Навигация складного устройства

Компонент навигации складного устройства — это библиотека, созданная по принципу компонента навигации Android. Он помогает разработчикам реализовать навигацию фрагментов в различных режимах экрана или адаптировать существующее приложение к шаблону навигации складного устройства;

Компонент навигации складного устройства состоит из трех ключевых частей:

  • Граф навигации. XML-ресурс, который содержит все сведения о навигации в одном централизованном расположении. Он такой же, как и граф из компонента навигации, предоставляемого Google.
  • FoldableNavHost. Пустой контейнер, отображающий пункты назначения из графа навигации. Реализация для навигации складного устройства — FoldableNavHostFragment.
  • FoldableNavController. Объект, управляющий навигацией приложения в FoldableNavHost.

Обзор

Приложения на складных устройствах и устройствах с двумя экранами могут отображаться на одном экране или быть распределены через компонент свертывания. При запуске приложения:

  • На устройстве с одним экраном будет виден только один фрагмент (A).
  • Если приложение преобразовано для просмотра через компонент свертывания, первый фрагмент (A) будет находиться на одной стороне свертывания, а другая останется пустой.

Если в первоначальном состоянии перейти к другому фрагменту (B), новый фрагмент будет открыт на конечном экране.

Если пользователь переходит к третьему фрагменту (C), он будет показан на конечном экране, а предыдущий фрагмент (B) будет перемещен на начальный экран.

  • При перемещении приложения на один экран все фрагменты с конечного экрана переходят на начальный, а фрагмент (C) располагается поверх остальных окон.
  • Когда приложение с положения на одном экране растягивается через свертывание или петлю, а навигационная стопка содержит более двух фрагментов, последний из них будет перемещен на конечный экран.

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

Изменение назначения области экрана для действий

Вы можете указать, где будет отображаться новый фрагмент, с помощью атрибута launchScreen в графе навигации. Возможные значения параметра launchScreen:

  • start — фрагмент будет открыт на первом экране
  • end — фрагмент будет открыт на втором экране
  • both — фрагмент будет охватывать всю отображаемую область

В этом примере навигации 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/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>

Важно!

Этот атрибут можно изменить, только непосредственно изменив XML-файл. Его нельзя изменить с помощью редактора Android Studio.

Образец

Вы можете скачать пример приложения для навигации, чтобы ознакомиться со всеми этими поведениями.

Импорт библиотеки в проект

  1. Добавьте зависимость в файл уровня модуля build.gradle:

    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. Если проект создан с использованием Java, необходимо добавить зависимость kotlin-stdlib в файл build.gradle на уровне модуля. (Это связано с тем, что некоторая часть библиотеки была создана с помощью Kotlin.)

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

Эти компоненты созданы по принципу компонента навигации, предоставляемого Google, поэтому в библиотеке навигации складного устройства содержится зависимость для него.

Создание графа навигации

Граф навигации — это XML-файл ресурсов со всеми путями навигации вашего приложения с использованием назначений и действий. Граф навигации можно создать с помощью редактора навигации Android Studio или вручную через редактор XML. Дополнительные сведения можно найти в статье о создании графа навигации.

Добавление NavHost к действию

Компонент навигации складного устройства предназначен для приложений с одним основным действием и несколькими назначениями фрагментов. Главное действие связано с графом навигации и будет содержать объект FoldableNavHostFragment, отвечающий за смену назначений фрагментов. Если в вашем приложении будет несколько действий, каждое из них будет иметь собственный граф навигации.

Это пример основного XML-файла макета действия, в котором показано, как задать атрибут 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>

FoldableNavHost можно также задать программно:

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

Дополнительные сведения о добавлении FoldableNavHost см. в статье о добавлении NavHost к действию.

Этот фрагмент кода можно использовать для перехода фрагментов в соответствии с правилами навигации складного устройства:

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

Обновление компонентов пользовательского интерфейса с помощью FoldableNavigationUI

FoldableNavigationUI — это аналогичный компонент, такой как NavigationUI в компоненте навигации Jetpack, и он содержит статические методы, управляющие навигацией с помощью верхней панели приложения, панели навигации и нижней структуры навигации. Вы можете найти дополнительные сведения о

FoldableNavigationUI содержит следующие методы, аналогичные предоставленным 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)

Перенос существующих приложений в систему навигации складного устройства

Существующие приложения, использующие компонент навигации, предоставляемый Google, могут добавлять функции складного устройства, выполнив следующие действия:

  1. Вместо NavHostFragment в представлении контейнера фрагментов используйте FoldableNavHostFragment, изменив

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

    значение

    <androidx.fragment.app.FragmentContainerView
         android:id="@+id/nav_host_fragment"
         android:name="androidx.navigation.FoldableNavHostFragment"
    
  2. Используйте findFoldableNavController, чтобы получить экземпляр для FoldableNavController и воспользоваться им для перехода внутри графа навигации путем изменения

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

    значение

    findFoldableNavController().navigate(R.id.action_next)
    
  3. Используйте FoldableNavigationUI вместо NavigationUI путем изменения

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

    значение

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