在Android中使用Navigation进行页面切换,我们可以使用下面方法之一来完成:
-
Fragment.findNavController()
-
View.findNavController()
-
Activity.findNavController(viewId: Int)
在LaunchFragment中我们点击textview的时候触发导航,修改onCreateView代码如下:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view: View = inflater.inflate(R.layout.fragment_launch, container, false)
val textView = view.findViewById<MaterialTextView>(R.id.launch_text)
textView.setOnClickListener {
findNavController().navigate(R.id.action_launchFragment_to_homeFragment);
}
return view
}
首先我们获取textview控件,然后设置其点击时导航至HomeFragment。
findNavController()定义如下:

接下来我们调用navigate方法导航到目标页面,navigate方法定义如下:

这里我们需要注意的是navigate方法参数是我们之前创建的导航Action的资源id,千万不要写fragment的id。

在很多情况下我们在fragment切换的时候需要传递参数,Navigation同样可以帮助我们完成这样的操作。
在导航编辑器中选择接收参数的页面,打开Attributes面板,然后添加待传递的参数:

输入参数名称、参数类型、参数是否可为 null,以及默认值(若需要):

这里我们就穿一个Boolean类型的变量,告诉HomeFragment我是LaunchFragment传递的参数。
添加参数后,Android Studio会自动在导航文件中添加对应的argument属性:

我们可以使用Bundle对象在目的地之间传递参数,这也是我们熟悉的一种方式。
在LaunchFragment中创建Bundle对象,然后使用navigate()将它传递给目的地:
textView.setOnClickListener {
val bundle = bundleOf("isFromLaunchFragment" to true)
findNavController().navigate(R.id.action_launchFragment_to_homeFragment,bundle)
}
其中bundleOf接收的参数为Pair类型,定义一个Pair类型,我们可以使用firstValue to sencondValue的方式。 如果你有多个参数那么在其之间用逗号分隔。

接下来就是十分熟悉的流程了,那就是在目的地也就是目标页面接收参数了。以后我们还是统一将目标跳转的页面称为目的地吧,好像官方的中文文档是这么翻译的。
在HomeFragment中使用arguments的getBoolean方法接收参数,然后显示在屏幕上:
val textView = view.findViewById<MaterialTextView>(R.id.home_text)
textView.text = arguments?.getBoolean("isFromLaunchFragment").toString()
这种方法不是我们推荐的,在Android Kotlin开发中,官方推荐使用Safe Args在不同的导航之间传递参数。这是在使用导航时传递数据的首选方式,因为它可以确保数据的安全。
首先,我们需要在project的build.gradle中添加下面的classpath:
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
其中nav_version在ext中定义:

接下来我们需要在Module的build.gradle中申明该safe args模块:
apply plugin: "androidx.navigation.safeargs.kotlin"
同步项目完成后,我们可以查看下启用 Safe Args后我们的项目有什么变化。

大家可以看到在生成的代码中多了一些文件,其中Android将为生成操作的每一个目的地创建一个类。该类的名称是在源目的地的名称后面加上“Directions”。在这里就是我们的LaunchFragment。
同时为每一个目的地都创建一个类。该类的名称是在目的地的名称后面加上“Args”。例如,如果目的地 Fragment 的名称为 HomeFragment,,则所生成的类将名为HomeFragmentArgs。可以使用该类的 fromBundle() 方法检索参数。
可以看下这两个文件的内容:


接下来我们使用Safe Args进行参数传递。
在LaunchFragment中,修改代码如下:
textView.setOnClickListener {
val action = LaunchFragmentDirections.actionLaunchFragmentToHomeFragment(true)
findNavController().navigate(action)
}
修改HomeFragment中代码:
class HomeFragment : Fragment() {
val args:HomeFragmentArgs by navArgs()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view: View = inflater.inflate(R.layout.fragment_home, container, false)
val textView = view.findViewById<MaterialTextView>(R.id.home_text)
textView.text = args.isFromLaunchFragment.toString()
return view
}
}
如果出现如下错误提示:


如果大家在Android Studio同步项目时遇见下载错误或者缓慢的问题,大家可以在mvnrepository.com/网站内搜索对应的资源,下载完成后拷贝到Android Studio对应的目录即可。
Android Studio这些文件的下载地址为:
windows:C:\Users\用户名.gradle\caches
比如我需要下载kotlin相关的插件:

这里我们顺带在学习一下下面一句代码:
val args:HomeFragmentArgs by navArgs()
我们查看下navArgs的帮助文档:

这是kotlin中属性委托的写法,语法是:
val/var <属性名>: <类型> by <表达式>。
简单来说,就是android帮我们实现了fragment中获取参数的公共方法,把只实现一次并放入一个库,然后供我们使用。
具体的内容大家可以参考官方文档:www.kotlincn.net/docs/refere…
在导航中我们还可以将Action作为全局操作,这个实现也很简单,在导航编辑器中选择添加Global Action:

在我们的fragment中在textview的点击事件中导航至HomeFragment,重写onCreate方法,打印log:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.i("HomeFragment", "onCreate")
}
LaunchFragment同理。
运行app:

点击textview:

在点击Home Fragment:

可以看到每点击一次,HomeFragment就会别重新创建。
这种全局Action适合我们在不同的页面返回至特定的页面,比如从各种详情页面到主页的操作。
另外我们经常会在启动的时候显示引导页面,这个页面一般来说只会在第一次显示,此时我们就可以使用条件导航。
这里做一个简单的演示:

修改showLaunchFragment的值,查看app运行效果。
在导航的使用中还有一个概念那就是深层链接,简单来说就是在我们的app外部来打开我们的程序。
这里我们先添加一个深层链接:

接下来我们还需要在AndroidManifest.xml中添加如下配置:

这里我们做个测试html:
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<meta id="viewport" name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,minimal-ui">
</head>
<html>
<input type="button" value="点击我打开Deeplink" onclick="javascrtpt:window.location.href='trainapp://qiushangge.com/home'">
</html>
然后拷贝至虚拟机:

使用浏览器打开该文件:

点击按钮唤醒app,此时app应该打开HomeFragment:
