目录
一,简介
Navigation是Jetpack组件库的一部分,于2018年推出;主要用于Fragment的管理,及之间的跳转等,使单Activity架构更简单;
二,使用条件
1,AndroidStudio版本需3.2及以上版本
2,module下的build.gradle添加依赖,根据自己项目的语言选择性添加依赖;
dependencies {
def nav_version = "2.3.0"
// 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"
}
关于依赖配置问题可以查看官网资料:https://developer.android.com/jetpack/androidx/releases/navigation
官网文档地址:https://developer.android.com/guide/navigation
本文使用的AndroidStudio版本号是4.0.1;
三,主要组成
- Navigation Graph :导航图是一个xml资源;创建于res/navigation/下;
- NavHostFragment:类似于一个容器,使Navigation Graph添加其中;
- NavController:处理Fragment间的跳转(Kotlin / Java对象);
四,主要功能
- 视觉导航图
- 按目的地和动作导航
- 过渡动画
- 菜单导航,底部导航和菜单抽屉导航
- 类型安全参数传递
- 深层连结
目的地可以理解为Fragment或者Activity还可以是另一个导航图;有的时候也叫目标;
五,使用
1,创建Navigation Graph导航图
右键项目new —>Android Resource File,填写File name名字自定义这里就叫navi_graph,Resource type选择Navigation,Directory name使用navigation;
注意:将导航图添加到项目中时,如果尚未将导航依赖项添加到应用程序的build.gradle文件中,则Android Studio会显示提示并为您添加依赖项。
<?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/navi_graph">
</navigation>
- <navigation> 是每个导航图的根节点。
- <navigation>包含一个或多个以<activity>或表示的目的地<fragment>。
- app:startDestination 是一个属性,它指定用户首次打开应用程序时默认启动的目的地。
2,导航编辑器
在导航编辑器中,可以直观地编辑导航图也可也直接编辑XML。
主要分不分:
1,“目标”面板:列出导航主机和“ 图形编辑器”中当前存在的所有目标。
2,图形编辑器:包含导航图的可视表示。可以在“ 设计”视图和“ 文本”视图中的基础XML表示形式之间切换。
3,属性:在导航图中显示当前选定项目的属性。
3,编辑导航图,将目的地添加到导航图
进入导航图navi_graph.xml编辑模式下,点击右上角的Split,一个导航图是包含所有的目的地和Action的XML资源文件;
第一种方式
点击进入New Destination,选择Create new Destination 以这个为例;创建一个Fragment,名字叫FirstFragment
xml资源如下
<?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"
android:id="@+id/navi_graph"
app:startDestination="@id/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name="com.example.navigationdemo.FirstFragment"
android:label="fragment_first"
tools:layout="@layout/fragment_first" />
<fragment
android:id="@+id/secondFragment"
android:name="com.example.navigationdemo.SecondFragment"
android:label="fragment_second"
tools:layout="@layout/fragment_second" />
<fragment
android:id="@+id/thirdFragment"
android:name="com.example.navigationdemo.ThirdFragment"
android:label="fragment_third"
tools:layout="@layout/fragment_third" />
</navigation>
多创建几个Fragment,后面讲跳转会用到;
注意:app:startDestination="@id/firstFragment"类似于MainActivity;fragment标签的属性可以通过单击一个目标以将其选中,然后在“ 属性”面板中修改和设置,也可直接编辑XML;
第二种方式
如果之前新建好了Fragment,这里可以点击进入New Destination找到之前新建好的Fragment引入即可,比如我之前已经有了一个TestFragment其布局为fragment_test;这里显示的是其布局文件名;
4,连接目的地
上面有提到一个导航图还包含Action标签,这个就是目的地间逻辑连接(或者说Fragment间的跳转),它可以在navigation标签下,也可以在fragment标签下;action标签还有destination 属性是表示目的地,要跳转到哪里的;还有个id属性,它和其他控件id含义一样,对比理解就好;在XML中通过action标签、属性destination,id就可实现目标的连接;
或者通过导航编辑器连接两个目的地:
在“ Design”选项卡中,将鼠标悬停在您要用户导航的目标的右侧。在目标的右侧上方将出现一个圆圈
点击圆圈并拖动鼠标,拖到想要连接的另一个目的地,两个目的地之间的结果线代表一个动作;
单击文本选项卡切换到XML视图。现在将action添加到id为firstFragment源目标。该action具有一个id和一个destination属性,destination属性值包含的是下一个目的地的id,如以下示例所示:
<?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"
android:id="@+id/nav_graph"
app:startDestination="@id/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name="com.ang.navigationtest.FirstFragment"
android:label="fragment_first"
tools:layout="@layout/fragment_first" >
<action
android:id="@+id/action_firstFragment_to_secendFragment"
app:destination="@id/secendFragment" />
</fragment>
<fragment
android:id="@+id/secendFragment"
android:name="com.ang.navigationtest.SecendFragment"
android:label="fragment_secend"
tools:layout="@layout/fragment_secend" />
<fragment
android:id="@+id/thirdFragment"
android:name="com.ang.navigationtest.ThirdFragment"
android:label="fragment_third"
tools:layout="@layout/fragment_third" />
</navigation>
请注意,要实际导航到目的地,仍然需要编写代码来执行导航。这个后面将跳转在具体说;
5,将NavHostFragment添加到Activity中
也是有两种方式:
第一种方式
在MainActivity的activity_main.xml布局中编写;具体代码如下,name是固定的不能修改,navGraph属性值是
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/nav_host_fragments"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"
app:navGraph="@navigation/navi_graph"/>
</androidx.constraintlayout.widget.ConstraintLayout>
app:defaultNavHost="true":让 Navigation 容器处理返回事件,在 Navigation 容器中如果有页面的跳转,点击返回按钮会先处理 容器中 Fragment 页面间的返回,处理完容器中的页面,再处理 Activity 页面的返回。如果值为 false 则直接处理 Activity 页面的返回。这里你能会发现,刚才navigation graph中爆红,现在消失了;
第二种方式:
如果你的Activity布局使用的约束布局的话,在布局的视图Split下,Containers中拖拽一个NavHostFragment,然后选择自己的导航图文件即可;别忘了设置约束哦
6,跳转
要实现目的地间的跳转,是通过NavController
获取NavController主要有三种方式
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View
好像这种也是可以的
FragmentManager supportFragmentManager = getActivity().getSupportFragmentManager();
NavHostFragment navHostFragment = (NavHostFragment) supportFragmentManager.findFragmentById(R.id.fragment);
NavController navController = navHostFragment.getNavController();
然后通过NavController 的navigate方法实现跳转;这里的resId可以是导航图中的目的地fragment的id,也可以是源目的地的action的id;
//navigate方法
public void navigate(@IdRes int resId) {
navigate(resId, null);
}
也可以通过如下方式实现跳转
view.findViewById(R.id.btn_to_secend).setOnClickListener( Navigation.createNavigateOnClickListener(R.id.secendFragment, null));
7,全局的action
上面有提到在navigation标签下也可以添加action,这个就是全局的action,可以解决多个源目的地跳转到同一个目的地,不用每个源目的地中都写同一个action了,准确的说应该是destination属性;
8,数据传递
NavController 的navigate跳转方法还有个重载方法,有个Bundle参数,所以可通Bundle实现目的地间的数据传递;
public void navigate(@IdRes int resId, @Nullable Bundle args) {
navigate(resId, args, null);
}
9,回退
既然NavController可以实现跳转,那么相似的功能回退呢,当然也可以实现,NavController有 navigateUp() 和 popBackStack() 两个方法可以返回上一级;
10,动态加载
可以在Fragment或者Activity中动态加载Navigation:
FragmentManager supportFragmentManager = getSupportFragmentManager();
NavHostFragment navHostFragment = (NavHostFragment) supportFragmentManager.findFragmentById(R.id.fragment);
NavController navController = navHostFragment.getNavController();
navController.setGraph(R.navigation.nav_graph);
NavHostFragment也是一个Fragment;可以当作一个Fragment使用;