可折叠设备导航

可折叠设备导航组件是一个基于 Android 导航组件构建的库。 它可帮助开发人员实现不同屏幕模式的片段导航,或者使现有应用程序适应可折叠设备导航模式;

可折叠设备导航组件由 3 个关键部分组成:

  • 导航图 - 一个 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 更新 UI 组件

FoldableNavigationUI 是与 Jetpack 导航组件中的 NavigationUI 类似的一个组件,包含使用顶部应用栏、导航抽屉和底部导航来管理导航的静态方法。 可在以下位置找到详细信息:

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. 在片段容器中使用 FoldableNavHostFragment 来取代 NavHostFragment,方式是更改

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

    to

    <androidx.fragment.app.FragmentContainerView
         android:id="@+id/nav_host_fragment"
         android:name="androidx.navigation.FoldableNavHostFragment"
    
  2. 使用 findFoldableNavController 获取 FoldableNavController 的实例并用它在导航图内进行导航,方式是更改

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

    to

    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)
    

    to

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