Google 致力于为黑人社区推动种族平等。查看具体举措

设计导航图

Navigation 组件使用导航图管理应用导航。导航图是一种资源文件,其中包含应用的所有目的地和逻辑连接(后者也称为“操作”,用户可以通过执行这些操作从一个目的地导航到另一个目的地)。您可以使用 Android Studio 中的 Navigation Editor 管理应用的导航图。

本主题包含有关设计应用导航图的最佳做法和建议。

顶级导航图

应用的顶级导航图应从用户启动应用时看到的初始目的地开始,且应包含他们在应用中四处浏览时看到的目的地。

图 1:顶级导航图。

嵌套图表

应用中的登录流程、向导或其他子流程通常是嵌套导航图的最佳表示形式。通过以这种方式嵌套独立的子导航流程,您可以更轻松地理解和管理应用界面的主流程。此外,嵌套图表可以重复使用。嵌套图表还提供一定程度的封装,即嵌套图表之外的目的地无法直接访问嵌套图表内的任何目的地。相反,这些目的地应 navigate() 到嵌套图表本身,在嵌套图表中,内部逻辑可以发生更改,而不会影响图表的其余部分。

以图 1 中的顶级导航图为例,假设您希望仅在用户首次启动应用时让其看到 title_screenregister 屏幕。之后,系统会存储用户信息。用户以后启动应用时,您应直接将其转到 match 屏幕。最佳做法应该是将 match 屏幕设置为顶级导航图的起始目的地,并将标题屏幕和注册屏幕移至嵌套图表中,如图 2 所示:

图 2:顶级导航图现在包含一个嵌套图表。

match 屏幕启动后,您可以检查是否有注册用户。如果用户未注册,您可以将其转到注册屏幕。如需详细了解条件导航情形,请参阅条件导航

将图表结构模块化的另一种方法是,通过父级导航图中的 <include> 元素,将一个图表包含在另一个图表中这样一来,就可以完全在单独的模块或项目中定义包含的图表,从而最大限度提高可重用性。

如果您的应用依赖包含导航图的库模块,您可以使用 <include> 元素引用这些导航图。

就我们的知识问答游戏示例而言,假设您想要将应用中以游戏为中心的部分分成单独的库模块,以便在多个应用中包含 in_gameresults_winnergame_over 屏幕,如以下示例所示:

<!-- App Module Navigation Graph -->
<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"
           app:startDestination="@id/match">

   <fragment android:id="@+id/match"
           android:name="com.example.android.navigationsample.Match"
           android:label="fragment_match">

       <!-- Launch into In Game Modules Navigation Graph -->
       <action android:id="@+id/action_match_to_in_game_nav_graph"
           app:destination="@id/in_game_nav_graph" />
   </fragment>

   <include app:graph="@navigation/in_game_navigation" />

</navigation>
<!-- Game Module Navigation Graph -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:id="@+id/in_game_nav_graph"
   app:startDestination="@id/in_game">

   <fragment
       android:id="@+id/in_game"
       android:name="com.example.android.gamemodule.InGame"
       android:label="Game">
       <action
           android:id="@+id/action_in_game_to_resultsWinner"
           app:destination="@id/results_winner"  />
       <action
           android:id="@+id/action_in_game_to_gameOver"
           app:destination="@id/game_over"  />
   </fragment>

   <fragment
       android:id="@+id/results_winner"
       android:name="com.example.android.gamemodule.ResultsWinner" >

       <!-- Action back to destination which launched into this in_game_nav_graph-->
       <action android:id="@+id/action_pop_out_of_game"
                           app:popUpTo="@id/in_game_nav_graph" />

   </fragment>

   <fragment
       android:id="@+id/game_over"
       android:name="com.example.android.gamemodule.GameOver"
       android:label="fragment_game_over"
       tools:layout="@layout/fragment_game_over" >

      <!-- Action back to destination which launched into this in_game_nav_graph-->
       <action android:id="@+id/action_pop_out_of_game"
                           app:popUpTo="@id/in_game_nav_graph" />

 </fragment>

</navigation>

您应该在主应用模块中纳入顶级图表,并对包含您需要引用的导航的任何模块进行 Gradle 引用。

全局操作

对于应用中的任何可通过多条路径到达的目的地,都应定义一项可导航到该目的地的相应全局操作。全局操作可用于从任意位置导航到某目的地。

下面我们将全局操作应用于库模块示例,该示例在获胜目的地和游戏结束目的地中定义了同一操作。您应将这些常见操作提取到一个全局操作,并从这两个目的地引用相应操作,如以下示例所示:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:id="@+id/in_game_nav_graph"
   app:startDestination="@id/in_game">

   <!-- Action back to destination which launched into this in_game_nav_graph-->
   <action android:id="@+id/action_pop_out_of_game"
                       app:popUpTo="@id/in_game_nav_graph"
                       app:popUpToInclusive="true"  />

   <fragment
       android:id="@+id/in_game"
       android:name="com.example.android.gamemodule.InGame"
       android:label="Game">
       <action
           android:id="@+id/action_in_game_to_resultsWinner"
           app:destination="@id/results_winner"  />
       <action
           android:id="@+id/action_in_game_to_gameOver"
           app:destination="@id/game_over"  />
   </fragment>

   <fragment
       android:id="@+id/results_winner"
       android:name="com.example.android.gamemodule.ResultsWinner" />

   <fragment
       android:id="@+id/game_over"
       android:name="com.example.android.gamemodule.GameOver"
       android:label="fragment_game_over"
       tools:layout="@layout/fragment_game_over" />

</navigation>

如需了解详情以及查看如何在 Fragment 中使用全局操作的示例,请参阅导航文档中的全局操作