Navigation Fragment

Posted by アライさん on 2019年11月07日

使用Navigation实现多Fragment单Activity应用

示例代码位置: https://gitee.com/alois/NavigationTest

MainActivity部分

activity_main.xml:

fragment容器属性:

  • app:defaultNavHost=”true” : true代表拦截系统的back按键。
  • app:navGraph=”@navigation/nav_main”:指定创建的navigation文件中的根navigation的id。

MainActivity:

需要重写onSupportNavigateUp

1
2
override fun onSupportNavigateUp() =
findNavController(R.id.nav_host_fragment).navigateUp()

nav_host_fragment即fragment容器的id。



Fragment部分

1
2
3
4
//返回上一fragment
Navigation.findNavController(it).navigateUp()
//跳转指定fragment,这里的id即Navigation中定义的action id
Navigation.findNavController(it).navigate(R.id.action_fragment1_to_fragment2)


Navigation文件

负责定义fragment的跳转行为

根navigation节点

设置activity_main.xml使用的id,app:startDestination指定初始的fragment。

fragment节点

定义所有fragment
包括id,name(包名.类名),action。

  • action节点:
    定义此fragment的所有跳转动作
    • id:指定id,Fragment类中跳转时调用这个id来触发action
    • app:destination: 指定要跳往的目标fragment的id
    • app:popUpTo:指定要返回到的fragment的id


跨fragment返回的方式

跨fragment返回时,直接调用相应的action

1
Navigation.findNavController(it).navigate(R.id.action_fragment2_back_fragment0)

由action中定义此action的类型是app:popUpTo,就可以完成返回



Fragment之间的参数传递

传参方式:

  • 通过共用viewmodel
  • 通过跳转时直接添加ars
  • 通过Safe Args

跳转时直接添加

1
2
3
4
//对返回无效
val args = Bundle()
args.putString("key","来自fragment2,time:$time")
Navigation.findNavController(it).navigate(R.id.action_fragment2_back_fragment0,args)

用Safe Args添加

Safe Args的优点是清晰定义并自动生成相关类,传参时直接调用方法即可,不需要考虑key是什么,类型是什么。

1. 添加环境

工程的gradle。properties中使用:

1
android.useAndroidX=true

项目的build.gradle中添加:

1
2
def nav_version = "2.1.0"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"

model的build.gradle中添加:

1
apply plugin: "androidx.navigation.safeargs.kotlin"

2. 在navigation中指定(可以通过UI界面直接添加)

添加完可能需要rebuild,自动生成一些类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<fragment
android:id="@+id/fragment1"
android:name="io.github.araisann.navigationtest.Fragment1"
android:label="Fragment1">
<action
android:id="@+id/action_fragment1_to_fragment2"
app:destination="@id/fragment2" />
<argument
android:name="myArgs0"
app:argType="string"
android:defaultValue='"I am Default Value"' />
<argument
android:name="myArgs1"
app:argType="integer"
android:defaultValue="0" />
</fragment>

3. 跳转时传入

1
2
val action = Fragment0Directions.actionFragment0ToFragment1("stringArgs",1)
Navigation.findNavController(it).navigate(action)

4. 接受传过来的参数

1
2
3
4
5
6
7
if(arguments!=null) {
val args = Fragment1Args.fromBundle(bundle = arguments!!)
//args.myArgs0
//args.myArgs1
}else{
//null
}