前言
Navigation 是应用程序设计的重要组成部分。 通过Navigation ,可以设计允许用户在应用内的不同内容区域中移动,移入和移出的交互。说白了其实是用来管理 APP 里页面跳转的。
使用
如果您想使用Android Studio导航,则必须使用Android Studio 3.3或更高版本。
要向项目添加导航图,请执行以下操作:
在“项目”窗口中,右键单击res目录,然后选择“ New > Android Resource File。 出现 New Resource File 对话框。
在“文件名”字段中键入名称,例如“nav_graph”。
从 Resource type下拉列表中选择Navigation。
单击确定。 发生以下情况:
在res目录中创建navigation资源目录。
在navigation目录中创建nav_graph.xml文件。
nav_graph.xml文件在导航编辑器中打开。 此XML文件包含导航图。单击 Text选项卡以切换到XML文本视图。 您应该看到一个空的导航图,如以下示例所示:
<?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android"> </navigation>
单击Design 返回“导航编辑器”。
创建destinations
- 在导航栏编辑器中, 点击New Destination , 然后点击 Create blank destination.
- New Android Component 弹窗出现, 输入一个Fragment Name.作为 Fragment类的名字
- 要让Android Studio为Fragment创建相应的布局资源文件,请选中Create layout XML旁边的框,然后在Fragment Layout Name字段中输入资源名称。
- 在 Source Language 下拉框中为类源文件选择 Kotlin 或者 Java 语言。
- 点击Finish.
startDestination 代表开始节点
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
app:startDestination="@id/blankFragment">
<fragment
android:id="@+id/blankFragment"
android:name="com.example.cashdog.cashdog.BlankFragment"
android:label="fragment_blank"
tools:layout="@layout/fragment_blank" />
<fragment
android:id="@+id/blankFragment2"
android:name="com.example.cashdog.cashdog.BlankFragment2"
android:label="Blank2"
tools:layout="@layout/fragment_blank_fragment2" />
</navigation>
连接destinations
使用action连接两个destinations,如下所示:
在“设计”选项卡中,将鼠标悬停在您希望用户导航的目标的右侧。目的地上会出现一个圆圈。单击并按住,将光标拖到希望用户导航到的目标上,然后释放。绘制一条线以指示两个目的地之间的导航。相应的会生成xml代码
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
app:startDestination="@id/blankFragment">
<fragment
android:id="@+id/blankFragment"
android:name="com.example.cashdog.cashdog.BlankFragment"
android:label="fragment_blank"
tools:layout="@layout/fragment_blank" >
<action
android:id="@+id/action_blankFragment_to_blankFragment2"
app:destination="@id/blankFragment2" />
</fragment>
<fragment
android:id="@+id/blankFragment2"
android:name="com.example.cashdog.cashdog.BlankFragment2"
android:label="fragment_blank_fragment2"
tools:layout="@layout/fragment_blank_fragment2" />
</navigation>
在谷歌官方demo中,实现了一组fragment之间的关系,在action中可以设置转场动画
<?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"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/title_screen">
<fragment
android:id="@+id/title_screen"
android:name="com.example.android.navigationsample.TitleScreen"
android:label="fragment_title_screen"
tools:layout="@layout/fragment_title_screen">
<action
android:id="@+id/action_title_screen_to_register"
app:destination="@id/register"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<action
android:id="@+id/action_title_screen_to_leaderboard"
app:destination="@id/leaderboard"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>
<fragment
android:id="@+id/register"
android:name="com.example.android.navigationsample.Register"
android:label="fragment_register"
tools:layout="@layout/fragment_register">
<action
android:id="@+id/action_register_to_match"
app:destination="@id/match"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>
<fragment
android:id="@+id/leaderboard"
android:name="com.example.android.navigationsample.Leaderboard"
android:label="fragment_leaderboard"
tools:layout="@layout/fragment_leaderboard">
<action
android:id="@+id/action_leaderboard_to_userProfile"
app:destination="@id/user_profile"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"/>
</fragment>
<fragment
android:id="@+id/match"
android:name="com.example.android.navigationsample.Match"
android:label="fragment_match"
tools:layout="@layout/fragment_match">
<action
android:id="@+id/action_match_to_in_game"
app:destination="@id/in_game"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"/>
</fragment>
<fragment
android:id="@+id/user_profile"
android:name="com.example.android.navigationsample.UserProfile"
android:label="fragment_user_profile"
tools:layout="@layout/fragment_user_profile">
<argument android:name="userName"
android:defaultValue="name"/>
<deepLink app:uri="www.example.com/user/{userName}" />
</fragment>
<fragment
android:id="@+id/in_game"
android:name="com.example.android.navigationsample.InGame"
android:label="Game"
tools:layout="@layout/fragment_in_game">
<action
android:id="@+id/action_in_game_to_resultsWinner"
app:destination="@id/results_winner"
app:popUpTo="@+id/match"
app:popUpToInclusive="false"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"
app:enterAnim="@anim/fade_in"
app:exitAnim="@anim/fade_out"/>
<action
android:id="@+id/action_in_game_to_gameOver"
app:destination="@id/game_over"
app:popUpTo="@id/match"
app:popUpToInclusive="false"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"
app:enterAnim="@anim/fade_in"
app:exitAnim="@anim/fade_out"/>
</fragment>
<fragment
android:id="@+id/results_winner"
android:name="com.example.android.navigationsample.ResultsWinner"
tools:layout="@layout/fragment_results_winner">
<action android:id="@+id/action_results_winner_to_leaderboard"
app:destination="@id/leaderboard"
app:popUpTo="@id/title_screen"/>
<action android:id="@+id/action_results_winner_to_match"
app:popUpTo="@id/match"/>
<action
android:id="@+id/action_results_winner_to_match2"
app:destination="@id/match" />
</fragment>
<fragment
android:id="@+id/game_over"
android:name="com.example.android.navigationsample.GameOver"
android:label="fragment_game_over"
tools:layout="@layout/fragment_game_over">
<action android:id="@+id/action_game_over_to_match"
app:popUpTo="@id/match"/>
</fragment>
</navigation>
修改Activity支持导航
activity为NavHost中的应用程序提供导航。 NavHost是一个当用户浏览您的应用程序时,目的地会被换入和换出空容器。
NavHost是一个接口,Navigation组件的默认NavHost实现是NavHostFragment。
xml实现
<FrameLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/background_light"
tools:context="com.example.android.navigationsample.MainActivity">
<fragment
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/navigation"/>
</FrameLayout>
navGraph 属性就是写刚才我们写的 nagation 文件
app:defaultNavHost =“true” 属性可确保NavHostFragment拦截系统“后退”按钮。 还可以通过覆盖AppCompatActivity.onSupportNavigateUp()并调用NavController.navigateUp来实现此行为,如下例所示:
@Override
public boolean onSupportNavigateUp() {
return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp();
}
当然也可以代码实现
NavHostFragment finalHost = NavHostFragment.create(R.navigation.example_graph);
getSupportFragmentManager().beginTransaction()
.replace(R.id.nav_host, finalHost)
.setPrimaryNavigationFragment(finalHost) // this is the equivalent to app:defaultNavHost="true"
.commit();
界面跳转
使用NavController类导航到目标。 可以使用以下静态方法之一检索NavController
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
拿到NavController后,使用其navigate()方法导航到目标。 navigate()方法接受资源ID。 ID可以是导航图的destination 或action中特定目标的ID。
view.findViewById<Button>(R.id.play_btn).setOnClickListener {
Navigation.findNavController(view).navigate(R.id.action_title_screen_to_register)
}
view.findViewById<Button>(R.id.leaderboard_btn).setOnClickListener {
Navigation.findNavController(view).navigate(R.id.action_title_screen_to_leaderboard)
}