文章目录
简介
Navigation组件用于管理应用内的页面跳转,它默认能支持Activity、Fragment、DialogFragment之间的跳转,但是一般被用来处理Fragment之间的跳转问题,google推出它的目的也是让单 Activity 应用成为首选架构。
使用Navigation组件可以屏蔽处理 FragmentTransaction 的复杂性,自动处理跳转和返回栈问题,此外还支持deepLink,并提供了帮助程序,用于将导航关联到合适的 UI 小部件,例如抽屉式导航栏和底部导航。
简单使用
- 导入依赖
val nav_version = "2.3.5"
// Java language implementation
// implementation("androidx.navigation:navigation-fragment:$nav_version")
// implementation("androidx.navigation:navigation-ui:$nav_version")
// Kotlin
implementation("androidx.navigation:navigation-fragment-ktx:$nav_version")
implementation("androidx.navigation:navigation-ui-ktx:$nav_version")
- 在res目录下新建navigation文件夹,在文件夹下新建导航的xml文件
- 编写导航文件
/**
* 导航文件根标签是navigation
* startDestination 用于指定默认加载的fragment
* navigation中默认可以添加三种页面的导航:fragment、activity、dialog
* 其中每个标签的 id 是在跳转时使用
* name 用于指定跳转到哪个具体页面
* label 页面说明
*/
<?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/mobile_navigation"
app:startDestination="@+id/navigation_home">
<fragment
android:id="@+id/navigation_home"
android:name="com.dean.playerdemo.ui.home.HomeFragment"
android:label="@string/title_home"/>
<activity
android:id="@+id/play_activity"
android:name="com.dean.playerdemo.PlayActivity"
android:label="PlayActivity"/>
<dialog
android:id="@+id/exit_dialog"
android:name="com.dean.playerdemo.ExitDialogFragment"
android:label="ExitDialogFragment"/>
</navigation>
- 在Activity的布局文件中添加页面容器,并用navGraph指定导航文件
/**
* 布局中添加fragment标签
* name必须是NavHostFragment
* defaultNavHost 是用来处理返回栈的
* navGraph 可以在xml中指定导航文件,也可以在代码中通过NavController指定
*/
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />
5、 现在直接运行就可以了,现在默认会加载startDestination指定的HomeFragment。
标签详解
fragment、activity、dialog 三个标签下可以使用其他标签用来指定跳转所需参数,页面内跳转事件、deeplink等信息。
这三个标签的具体使用和管理应用内的页面都需要通过NavController,所以先要获取NavController。
- fragment中获取NavController
//kotlin 中,默认kotlin为Fragment写了扩展函数findNavController
val navController = findNavController()
// java中
NavController navController = Navigation.findNavController(getView());
- Activity中获取NavController
// kotlin中,默认kotlin为Activity写了扩展函数findNavController
val navController = findNavController(R.id.nav_host_fragment)
// java中
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
跳转事件 <action>
使用NavController.navigate跳转时,可以直接传入一个已经定义好的具体的页面:
// R.id.play_activity就是之前定义好的activity
navController.navigate(R.id.play_activity)
但是最好还是使用action来跳转,这样便于管理和添加动画等效果,action可以分为两类
- 全局action,在当前graph中任意页面都可以使用
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mobile_navigation"
app:startDestination="@+id/navigation_home">
......
<action
android:id="@+id/global_to_no_internet_tip"
app:destination="@id/network_tip_fragment" />
......
</navigation>
- 局部action,只能在定义该action的页面内使用:
定义action:
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mobile_navigation"
app:startDestination="@+id/navigation_home">
......
<fragment
android:id="@+id/navigation_home"
android:name="com.dean.playerdemo.ui.home.HomeFragment"
android:label="@string/title_home">
<action
android:id="@+id/homefragment_action_to_play"
app:destination="@id/play_activity" />
</fragment>
<activity
android:id="@+id/play_activity"
android:name="com.dean.playerdemo.PlayActivity"
android:label="PlayActivity"/>
......
</navigation>
跳转(只能在HomeFragment内使用):
findNavController().navigate(R.id.homefragment_action_to_play)
action 标签有很多其他的属性,想要了解这些属性,需要先创造一个虚拟场景,假设有ABC三个页面,现在已经在栈中的页面是A和B,现在定义一个B跳转到C的Action:
<action
android:id="@+id/page_b_action_to_page_c"
app:destination="@id/Page_C"
app:enterAnim="@anim/fragment_close_enter"
app:exitAnim="@anim/fragment_close_exit"
app:popUpTo="@id/Page_A"
app:popUpToInclusive="true"
app:popEnterAnim="@anim/fragment_close_exit"
app:popExitAnim="@anim/fragment_fade_enter"
app:launchSingleTop="true" />
- popUpTo 和 popUpToInclusive
popUpTo指定出栈时回到哪个页面,这边写的是Page_A,那么Page_C出栈时会直接回到Page_A,Page_B跳转到Page_C后的栈内元素是AC。
popUpToInclusive用来判断到达指定元素时是否把指定元素也出栈,默认是false,如果设置为True,栈内元素就只剩下C,A也会出栈,这一般可以用来清空返回栈。 - enterAnim 和 popExitAnim
enterAnim是action目的地进入的动画,即Page_C的入场动画
popExitAnim是action目的地离开的动画,即Page_C的出场动画 - exitAnim 和 popEnterAnim
exitAnim是action所在元素离开的动画,即Page_B的出场动画
popEnterAnim是action所在元素进入的动画,即Page_B的入场动画 - lau