Navigation:管理 Fragment 的新架构模式,如果你想,整个 App 只需要一个 Activity 即可完成;
上图中ABC三个页面是由三个 Fragment 完成,交由 Navigation 管理即可实现;
想要使用 Navigation 组件需要添加依赖,且 Android Studio 3.2 版本以上;
实现非常简单,三步完成:
① 创建 navigation 目录
② 创建 navigation.xml 文件
③ Activity 关联 navigation
最炫的是预览
第一步 :( 太简单了)
res目录下 >>> New >>> New Resource Directory
第二步 创建 navigation.xml 文件
navigation目录下 >>> New >>> Navigation Resource File
<!-- id ( xml 文件 navigation 的 id )
startDestination ( 默认加载首个页面,第一个 Fragment. 注:不是 Fragment 类名,是指向下面 fragment 节点的 id )-->
<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/nav_demo"
app:startDestination="@+id/fragment_a">
<!-- 节点
id ( 节点 id,跳转指向使用 )
name ( Fragment 路径 )
layout ( Fragment 布局,用于浏览 )
label ( 标签名称,记录这个节点的标签信息,暂时没用到 ) -->
<fragment
android:id="@+id/fragment_a"
android:name="FragmentA"
android:label="BlankFragment"
tools:layout="@layout/fragment_a">
<!-- 负责跳转
id ( 跳转id,页面中执行跳转时使用 )
destination ( 跳转的目标 fragment 的 id )
剩下四个属性 ( 跳转动画 ) -->
<action
android:id="@+id/action_a_to_b"
app:destination="@+id/fragment_b"
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/fragment_b"
android:name="FragmentB"
android:label="BlankFragment"
tools:layout="@layout/fragment_b">
<action
android:id="@+id/action_b_to_c"
app:destination="@+id/fragment_c"
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/fragment_c"
android:name="FragmentC"
android:label="BlankFragment"
tools:layout="@layout/fragment_c"/>
</navigation>
第三步:Activity 关联 navigation
首先看下 Activity 布局文件
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NavActivity">
<!-- 关联 navigation 和 Activity
name ( 告知 fragment 使用 navigation 模式关键属性,固定值,直接复制即可 )
defaultNavHost ( true 回退操作是否进行拦截交给 Navigation 管理 )
navGraph ( navigation 的 xml 文件 )
-->
<fragment
android:id="@+id/nav_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_demo" />
</androidx.constraintlayout.widget.ConstraintLayout>
然后看下 Activity 代码
class NavActivity : AppCompatActivity() {
/**
* 控制器 ( 可以在 Activity 和 Fragment 中使用 )
* 负责操作 Navigation 框架下的 Fragment 的跳转与退出、动画、监听当前Fragment信息
*/
lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_nav)
// R.id.nav_fragment 是 Activity 布局里 fragment 控件的 id
navController = Navigation.findNavController(this, R.id.nav_fragment)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp()
}
// 如果想要中间 Fragment 点击返回键关闭整个 Activity 时,重写 onBackPressed()
override fun onBackPressed() {
// 得到当前目的地
val currentDes = navController.currentDestination
if (currentDes is FragmentNavigator.Destination) {
when (currentDes.className) {
// 如果当前页是 FragmentB 则直接退出 Activity
FragmentB::class.java.name -> finish()
else -> super.onBackPressed()
}
} else {
super.onBackPressed()
}
}
}
附: Fragment 之间跳转
/**
* 两种方式都可实现跳转,根据不同场景选择即可
* action_a_to_b ( xml 中 Action 的 id )
*/
NavHostFragment.findNavController(this).navigate(R.id.action_a_to_b)
Navigation.findNavController(view).navigate(R.id.action_a_to_b)
参数传递接收
// 跳转时添加 Bundle 传递参数
val bundle = Bundle()
bundle.putString("nav_param_fragment_b", "fragmentB Param")
Navigation.findNavController(view).navigate(R.id.action_b_to_c, bundle)
// 上级 Fragment 传参
val fragmentParam = arguments?.getString("nav_param_fragment_b")
// Activity 传参,每个 Fragment 都可获取 ( 其他页面传递参数至 NavActivity )
val activityParam = activity?.intent?.getStringExtra("nav_param_activity") ?: ""