项目中多使用单个Activity嵌套多个Fragment的UI架构模式,但是对Fragment的管理一直比较麻烦,通常使用FragmentManager和FragmentTransaction来管理Fragment之间的切换,页面的切换通常还包括对应用程序APPBar的管理,Fragment之间的切换动画,以及Fragment间的参数传递,纯代码方式使用不是很友好,并且Fragment和APPBar在管理和使用中比较混乱,为此JetPack提供了Navigation组件,旨在方便管理页面和APPBar。
使用Navigation的优势
工作方式:
当你想切换Fragment时,使用NavController对象,告诉你想要去Navigation Graph中的哪个Fragment,NavController会将你想要去的Fragment展示在NavHostFragment中
添加依赖
implementation 'androidx.navigation:navigation-fragment:2.3.0'
implementation 'androidx.navigation:navigation-ui:2.3.0'
在res下新建选择Android resourceFile新建一个Navigation Graph文件。设置名称为"nav_graph",选择种类为"Navigation"。
所生成的xml文件和布局文件相似,有design和text两个面板。
我们在MainActivity的布局文件中添加一个NavHostFragment作为所有Fragment的容器
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
androidx.constraintlayout.widget.ConstraintLayout>
ATTENTION
android:name="androidx.navigation.fragment.NavHostFragment"
这一样代码告诉系统,这是一个特殊的Fragment。
app:defaultNavHost="true"
将app:defaultNavHost="true"设置为true,则该Fragment会自动处理系统返回键,即当用户按下手机的返回按键时,系统能自动将当前展示的Fragment退出。
app:navGraph="@navigation/nav_graph"
app:navGraph属性用于设置Fragment对应的导航图。设置这个属性后,我们在nav_graph导航图上,就可以看见我们设置的NavHostFragment
单击Create new destination,创建一个destination
一个destination代表一个路由页面。我们创建一个MainFragment。这时我们的na v_graph的界面出现一个main_fragment。
<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_graph"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.example.navigationdemo.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main" >
fragment>
navigation>
navigation标签下会出现一个app:startDestination属性,该属性指定起始destination为mainFragment。
单击Create new destination,创建一个SecondFragment。单击mainFragment,用鼠标选中右侧的圆圈,并拖拽到右边的SecondFragment。
拖拽后,在看XML代码,会出现一个action标签,并自动给出id。
我们在MainFragment中添加一个Button跳转到SecondFragmen。
//跳转到第二个Fragment
mBtnToSecondFragment.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(v).navigate(R.id.action_mainFragment_to_secondFragment);
}
});
//第二种方法
mBtnToSecondFragment.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.createNavigateOnClickListener(R.id.action_mainFragment_to_secondFragment);
}
});
在res新建anim,打开导航文件的Design面板。选择Attribute,选择Animation。
设置完动画,我们可以看见action标签里就加上了动画属性,运行可以看见效果
//跳转到第二个Fragment
mBtnToSecondFragment.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavOptions options = new NavOptions.Builder()
.setEnterAnim(android.R.anim.fade_in)
.setExitAnim(android.R.anim.fade_out)
.setPopEnterAnim(android.R.anim.fade_in)
.setPopExitAnim(android.R.anim.fade_out)
.build();
Navigation.findNavController(v).navigate(R.id.action_mainFragment_to_secondFragment,null,options);
}
});