可折叠设备导航
可折叠设备导航组件是一个基于 Android 导航组件构建的库。 它可帮助开发人员实现不同屏幕模式的片段导航,或者使现有应用程序适应可折叠设备导航模式;
可折叠设备导航组件由 3 个关键部分组成:
- 导航图 - 一个 XML 资源,它在一个集中位置汇集与导航相关的所有信息。 它与 Google 提供的导航组件中的相同。
- FoldableNavHost - 一个空容器,显示导航图中的目的地。 可折叠设备导航的实现为
FoldableNavHostFragment
。 - FoldableNavController - 一个对象,用于管理
FoldableNavHost
中的应用导航。
概述
双屏和可折叠设备上的应用程序可显示在单个屏幕上,也可跨折叠功能显示。 当应用程序首次启动时:
- 在单屏中,将只显示一个片段 (A)。
- 如果应用程序跨折叠功能呈现,则第一个片段 (A) 将位于折叠的第一侧,折叠的另一侧将为空白。
在初始状态中,如果导航到第二个片段 (B),则新片段将在结束屏幕上打开。
如果用户导航到第三个片段 (C),该片段将显示在结束屏幕上,上一个片段 (B) 将移动到开始屏幕。
- 当应用从跨屏移动到单屏时,结束屏幕中的所有片段将移动到开始屏幕,并且 (C) 显示在顶部。
- 当应用从单屏移动到跨折叠或跨铰链显示,并且导航堆栈具有两个以上的片段时,最后一个片段将移动到结束屏幕。
更改操作显示区域目的地
可使用导航图中的 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 编辑器来修改它。
示例
可下载此导航示例应用来查看所有这些行为。
如何将库导入项目
将依赖关系添加到模块级 build.gradle 文件:
如果项目是使用 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 提供的导航组件的现有应用程序可按照以下步骤添加可折叠设备功能:
在片段容器中使用
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"
使用
findFoldableNavController
获取FoldableNavController
的实例并用它在导航图内进行导航,方式是更改findNavController().navigate(R.id.action_next)
to
findFoldableNavController().navigate(R.id.action_next)
使用
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)