为了账号安全,请及时绑定邮箱和手机立即绑定

Navigation(一)使用Navigation

2021.04.02 15:52 273浏览

一 Navigation主要元素

  • Navigation Graph 一种xml资源文件,包含应用程序的所有页面以及页面之间的关系。
  • NavHostFragment 一种特殊的Fragment,Navigation Graph中的Fragment正是通过这个特殊的Fragment启动的。
  • NavController 导航控制器,主要用来完成页面切换工作。

二 使用Navigation

2.1 添加依赖

Navigation需要依赖几个支持库,所以在使用Navigation之前需要在gradle文件中导入相关库:

implementation "androidx.navigation:navigation-fragment-ktx:2.3.2"
implementation "androidx.navigation:navigation-ui-ktx:2.3.2"

如果要在导航页面之前传递类型安全的参数,需要添加Safe Args插件并且配置classpath:

id 'androidx.navigation.safeargs'
//id 'androidx.navigation.safeargs.kotlin'
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.2"

2.2 创建导航图

Res右键New Resource File创建一个资源文件,类型名字写成nav_graph,类型选择Navigation

image.png
就会创建一个导航图文件,里边包含以下内容:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph">
</navigation>

2.3 添加NavHostFragment

NavHostFragment是一个特殊的Fragment,需要添加到Activity的布局文件中。

<androidx.fragment.app.FragmentContainerView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph"/>
  • name属性指定NavHost的实现类,这里是NavHostFragment。
  • defaultNavHost=“true” 拦截系统返回键,当用户按下返回键时系统会将正在展示的Fragment返回。
  • navGraph属性 关联导航图。

2.4 为导航图添加目的地

首先需要创建两个Fragment,FirstFragment和SecondFragment,并且将这两个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/fragmentFirst">
    <fragment
        android:id="@+id/fragmentFirst"
        android:name="com.example.navigationtest.FirstFragment"
        android:label="fragment_first"
        tools:layout="@layout/fragment_first"/>
    <fragment
        android:id="@+id/fragmentSecond"
        android:name="com.example.navigationtest.SecondFragment"
        android:label="fragment_second"
        tools:layout="@layout/fragment_second"/>
</navigation>
  • id 必填项,后面fragment跳转的时候要用到
  • name Fragment的全路径
  • layout Fragment的布局

2.5 添加跳转action

为了达到跳转的目的,需要为fragment添加用于跳转的action。

<action 
       android:id="@+id/first_to_second"
       app:destination="@id/fragmentSecond"/>

其中,destination指定了要跳转到的fragment,这也就是为什么在导航文件中创建fragment时要指定id的原因。定义好action之后,在FirstFragment中添加跳转的点击事件,使用Navigation将页面导航到SecondFragment中:

val view=inflater.inflate(R.layout.fragment_first, container, false)
        val binding = FragmentFirstBinding.bind(view)
        binding.btnFirst.setOnClickListener {
            Navigation.findNavController(view!!).navigate(R.id.first_to_second)
        }

navigate方法接收的参数就是前面定义的action。

2.6 添加转场动画

刚刚创建的跳转过程默认是没有动画效果的,现在把转场动画效果加上。修改导航文件中的action,添加动画属性:

<action
       android:id="@+id/first_to_second"
       app:destination="@id/fragmentSecond"
       app:enterAnim="@anim/nav_default_enter_anim"
       app:exitAnim="@anim/nav_default_exit_anim"
       app:popEnterAnim="@anim/nav_default_pop_enter_anim"
       app:popExitAnim="@anim/nav_default_pop_exit_anim"/>

运行程序,切换页面时就可以看到动画效果。

2.7 使用NavigationUI

2.7.1 NavigationUI的意义

在Navigation组件中,导航图是很重要的一部分,可以帮助我们了解页面之间的关系,并且快速完成页面间的切换,而在页面切换的过程中还伴随着菜单栏的变化。对于不同的页面,AppBar中的menu菜单很可能是不一样的。并且AppBar中的按钮和菜单同样可能承担着页面切换的工作,为了统一管理,JetPack引入了NavigationUI组件来将AppBar与Navigation中的导航图关联到一起。

2.7.2 NavigationUI的使用分析
  • 首先需要创建一个settingFragment并且关联到导航图文件中
 <fragment
     android:id="@+id/fragmentSetting"
     android:name="com.example.navigationtest.SettingFragment"
     tools:layout="@layout/fragment_setting"
     android:label="fragment_setting"/>
  • 创建菜单文件menu_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@id/fragmentSetting"
        android:icon="@drawable/ic_launcher_background"
        android:title="设置" />
</menu>

item的id需要和导航文件中的settingFragment保持一致,否则会无法跳转到settingFragment。

  • 在activity中实现跳转
class NavigationActivity : AppCompatActivity() {
    private var navController: NavController? =null
    private var appBarConfig:AppBarConfiguration?=null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityNavigationBinding.inflate(layoutInflater)
        setContentView(binding.root)
//        navController = Navigation.findNavController(this@NavigationActivity,R.id.nav_host_fragment)
        val navHost = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
        navController = navHost!!.findNavController()
        appBarConfig = AppBarConfiguration(navController!!.graph)
        NavigationUI.setupActionBarWithNavController(this, navController!!, appBarConfig!!)

    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        super.onCreateOptionsMenu(menu)
        menuInflater.inflate(R.menu.menu_settings,menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return NavigationUI.onNavDestinationSelected(item,navController!!)||super.onOptionsItemSelected(item)
    }

    override fun onSupportNavigateUp(): Boolean {
        return NavigationUI.navigateUp(navController!!,appBarConfig!!)||super.onSupportNavigateUp()
    }
}

AppBarConfiguration用于AppBar的配置,NavController用于页面导航。通过调用NavigationUI.setupActionBarWithNavController将NavigationUI、AppBarConfiguration以及NavController绑定到一起,最后通过onOptionsItemSelected完成菜单项的点击跳转。后面如果需要增加菜单项,只需要添加对应的fragment然后修改菜单文件即可。

2.7.3 监听页面切换

如果想要在页面切换的时候做一些其他操作,可以使用NavController提供的addOnDestinationChangedListener方法监听切换过程:

 navController!!.addOnDestinationChangedListener { _, _, _ ->
            Toast.makeText(this@NavigationActivity, "完成页面切换", Toast.LENGTH_LONG).show()
        }

2.8 传递参数

2.8.1 使用Bundle传递参数

这种方式属于传统方式传参,需要把用到的参数按照键值对的方式定义好,在跳转的时候将Bundle作为参数传递过去,然后在另一个页面接收:

//传参
 val binding = FragmentFirstBinding.bind(view)
     binding.btnFirst.setOnClickListener {
            val bundle = bundleOf("name" to "yang","age" to 32)
            Navigation.findNavController(view!!).navigate(R.id.first_to_second,bundle)
}
//接收参数     
val name=arguments?.getString("name")
binding.tvName.text = name
2.8.2 使用SafeArgs插件传参

使用SafeArgs插件之前需要先在gradle文件中配置该插件:

classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.2"
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'androidx.navigation.safeargs'
//    id 'androidx.navigation.safeargs.kotlin'
}

插件导入成功之后就可以定义参数了,在导航文件中为要传递参数的fragment中添加两个argument标签,用来定义参数:

 <argument
        android:name="name"
        android:defaultValue=""
        app:argType="string" />

 <argument
        android:name="age"
        android:defaultValue="0"
        app:argType="integer" />

在FirstFragment中传递参数,有两种方式传递,Bundle和Directions,先来卡一下使用Bundle的方式:
Bundle传参

 val bundle = FirstFragmentArgs.Builder().setName("yang").setAge(32).build().toBundle()
            Navigation.findNavController(view!!).navigate(R.id.first_to_second,bundle)

这里和传统使用Bundle方式的区别就是生成Bundle的方式不一样了,当引用safeargs插件之后就会为每个Fragment自动生一个带有Args后缀的类,里边已经为我们定义的name和age两个参数创建了set方法。

Directions传参

val firstFragmentDirections =  FirstFragmentDirections.firstToSecond().setName("yang").setAge(32)
            Navigation.findNavController(view!!).navigate(firstFragmentDirections)

SafeArgs会自动为每个目的地创建一个Directions类,firstToSecond(),这个方法返回一个FirstFragmentDirections对象,对象内部已经实现了name和age字段的get/set方法,调用set方法即可完成参数的创建,最后将firstFragmentDirections作为navigate()方法的参数即可。

接收参数
接收参数统一使用前文介绍的接收方式即可:

val name=arguments?.getString("name")
binding.tvName.text = name

三 结语

关于Navigation的基本使用介绍到这里,下一篇文章介绍Navigation中另外一个比较重要的知识点DeepLink的用法。

点击查看更多内容
0人点赞

若觉得本文不错,就分享一下吧!

评论

相关文章推荐

正在加载中
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消