1 github 代码地址
边看代码边读文章效果更佳呦
2 Navigation 简单使用
Navigation 是 google Jetpack 组件库的应用导航解决方案,用于 Activity、Fragment 之间进行页面跳转。Navigation 会提供一个 xml 负责管理各个导航组件直接的关系
2.1 使用入门
2.1.1 简单实现两个 fragment 的跳转
代码所在分支:simple-use
1、添加依赖
dependencies { def 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" // Feature module Support implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version" // Testing Navigation androidTestImplementation "androidx.navigation:navigation-testing:$nav_version" // Jetpack Compose Integration implementation "androidx.navigation:navigation-compose:1.0.0-alpha10" } 复制代码
2、创建导航关系图
在 xml 文件夹下面创建一个 navigation1.xml 文件,用来存放两个 fragment 之间的路由关系,代码如下:
<?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/jjj" <!----> app:startDestination="@id/originFragment"> <fragment android:id="@+id/originFragment" android:name="com.mage.navigationdemo.OriginFragment" android:label="fragment_origin" tools:layout="@layout/fragment_origin" > <action android:id="@+id/action_originFragment_to_destiationFragment" app:destination="@id/destiationFragment" /> </fragment> <fragment android:id="@+id/destiationFragment" android:name="com.mage.navigationdemo.DestiationFragment" android:label="fragment_destiation" tools:layout="@layout/fragment_destiation" /> </navigation> 复制代码
下面表格是各个重要标签属性的说明
属性标签名 | 作用 |
navigation | 导航组件的根标签 |
startDestination | 第一次进入页面展示的组件标签 |
fragment-id | 视图中 fragment 的 id,导航用 |
fragment-name | Fragment 或 Activity 的全类名 |
action-destination | 目的地的视图 id |
3、Activity 布局文件配置
在 activity 的布局文件中加入导航组件容器
<androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:defaultNavHost="true" app:navGraph="@navigation/nav_graph" /> 复制代码
属性标签名 | 作用 |
FragmentContainerView-name | 固定写法 |
FragmentContainerView-navGraph | 所关联的 xml 视图 |
FragmentContainerView-navGraph | 确保可以拦截系统的返回键,如果设置 false 就无法进行回退操作 |
4、创建两个 Fragment
创建 OriginFragment.kt DestiationFragment.kt 两个 Fragment,这两个 fragment 就是常规的 fragment 创建 在第二条的 navigation 中我们将 OriginFragment 设置为了主 Fragment,既 activity 打开后首次展示的 Fragment
5、实现 OriginFragment 跳转到 DestiationFrament
OriginFragment 中添加按钮点击事件,navigate 可以实现跳转的 DestiationFragment 的效果
btn.setOnClickListener { val findNavController = findNavController() findNavController.navigate(R.id.destiationFragment) } 复制代码
R.id.destiationFragment 即是第 2 步中我们在 navigation 中给 DestiationFrgment 设置的 id
6、最终实现效果展示
2.1.2 实现 activity 跳转到 activity 操作
代码实现在分支:activity2activity
2.1.1 中实现的是 Fragment 和 Fragment 直接的路由,本例中我们要实现从一个 Activity 跳转到另一个 Activity 的操作
1、基本配置
本例中实现 MainActivity 跳转到 DesActivity 的操作,MainActivity 中依然要添加一个 FragmentContainerView 控件以及一个 OriginFragment。
2、导航图代码
本例导航图中需要配置 MainActivity 和 DesActivity,DesActivity 就是我们要跳转到的 Activity
<?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/navigation1" app:startDestination="@id/originFragment"> <activity android:id="@+id/mainActivity" android:name="com.mage.navigationdemo.MainActivity" android:label="activity_main" tools:layout="@layout/activity_main" /> <activity android:id="@+id/desActivity" android:name="com.mage.navigationdemo.DesActivity" android:label="activity_des" tools:layout="@layout/activity_des" /> <fragment android:id="@+id/originFragment" android:name="com.mage.navigationdemo.OriginFragment" android:label="fragment_origin" tools:layout="@layout/fragment_origin" /> </navigation> 复制代码
3、MainActivity 中点击跳转的代码
MainActivity 中添加按钮点击进行跳转操作: R.id.nav_host_fragment 就是 MainActivity 布局文件中 FragmentContainerView 的 id,我们通过 id 拿到 NavController,通过 Controller 实现跳转到 DesActivity 的操作
findViewById<Button>(R.id.btn_des).setOnClickListener { findNavController(R.id.nav_host_fragment).navigate(R.id.desActivity) } 复制代码
4、实现效果
3 导航间数据传递
导航间数据传递有两种方式 Bundle 和 Safe Args 两种方式,其中 Safe Args 需要基于 gradle 插件,下面分别介绍一下两种方式:
3.1 Bundle 方式传递数据
这个很简单直接上代码
btn.setOnClickListener { val findNavController = findNavController() findNavController.navigate(R.id.destiationFragment, bundleOf("param1" to "我是AFragment传过来的参数")) } 复制代码
3.2 Safe Args 方式传递数据
这种方式需要基础插件
该插件可以生成简单的 object 和 builder 类,以便以类型安全的方式浏览和访问任何关联的参数
3.2.1 插件集成方法
1 添加跟 gradle 依赖
def nav_version = "2.3.5" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" 复制代码
2 app.gradle中加入插件
plugins { id 'androidx.navigation.safeargs' } 复制代码
3.2.2 插件说明(参考官方)
启用 Safe Args 后,生成的代码会为每个操作包含以下类型安全的类和方法,以及每个发送和接收目的地。
- 为生成操作的每一个目的地创建一个类。该类的名称是在源目的地的名称后面加上“Directions”。例如,如果源目的地是名为 SpecifyAmountFragment 的 Fragment,则生成的类的名称为 SpecifyAmountFragmentDirections。 该类会为源目的地中定义的每个操作提供一个方法。
- 对于用于传递参数的每个操作,都会创建一个 inner 类,该类的名称根据操作的名称确定。例如,如果操作名称为 confirmationAction,,则类名称为 ConfirmationAction。如果您的操作包含不带 defaultValue 的参数,则您可以使用关联的 action 类来设置参数值。
- 为接收目的地创建一个类。该类的名称是在目的地的名称后面加上“Args”。例如,如果目的地 Fragment 的名称为 ConfirmationFragment,,则生成的类的名称为 ConfirmationFragmentArgs。可以使用该类的 fromBundle() 方法检索参数。
3.2.3 代码
代码所在分支:deliverparams
1、导航图代码
CFragment 的标签体中的标签就是 CFragment 要接收的数据
<?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/jjj" app:startDestination="@id/AFragment"> <fragment android:id="@+id/AFragment" android:name="com.mage.navigationdemo.AFragment" android:label="fragment_origin" tools:layout="@layout/fragment_origin" > <action android:id="@+id/action_AFragment_to_destiationFragment" app:destination="@id/destiationFragment" /> </fragment> <fragment android:id="@+id/destiationFragment" android:name="com.mage.navigationdemo.BFragment" android:label="fragment_destiation" tools:layout="@layout/fragment_destiation" /> <fragment android:id="@+id/CFragment" android:name="com.mage.navigationdemo.CFragment" android:label="fragment_c" tools:layout="@layout/fragment_c" > <argument android:name="data" app:argType="string" android:defaultValue="1" /> </fragment> </navigation> 复制代码
2、源 Fragment 跳转代码
插件会自动生成 CFragmentArgs 参数类
btnTC.setOnClickListener { AFragmentDirections.actionAFragmentToDestiationFragment() val args = CFragmentArgs.Builder().setData("AFragment传输到CFragment的数据").build().toBundle() val findNavController = findNavController() findNavController.navigate(R.id.CFragment,args) } 复制代码
3、目的地 Fragment 解析参数代码
var cFragmentArgs: CFragmentArgs? = null override fun onAttach(context: Context) { super.onAttach(context) arguments?.let{ cFragmentArgs = CFragmentArgs.fromBundle(it) } } 复制代码
4、实现效果