Jetpack之Navigation和NavigationUI

770 阅读2分钟

依赖

   implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'
    implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'

navigation的主要元素

  1. Navigation Graph 一种xml资源文件,包含应用所有的页面以及页面之间的关系,也就是fragment的放置的地方,
  2. NavHostFragement 一种特殊的fragment, 可以理解为fragment的容器,是fragment展示UI的地方,Navigation Graph中的fragment通过NavHostFragement展示
  3. NavController 控制器,用于在代码中完成Navigation Graph中具体的页面切换工作

Navigation Graph的创建

res文件夹 -new - Android Resource File,新建Navigation Graph文件。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

添加NavHostFragment

NavHostFragment是一个特殊的Fragment,添加到activity的布局中。

  1. 创建完nav_graph文件后引入,并告诉系统这是一个特殊的fragment-NavHostFragment
  2. app:defaultNavHos
  3. app:defaultNavHost="true" 自动处理系统返回键
  4. navGraph 属性 设置该Fragment对应的导航图-
    <fragment
        android:id="@+id/nav_host_fragment_container"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph"/>

创建destination

指定默认第一个页面 app:startDestination 第一个要展示的fragment 在这里插入图片描述 指定你要去的页面 在这里插入图片描述

NavController完成导航并传递参数

第一个fragment中完成点击跳转并传递参数

        var view = inflater.inflate(R.layout.fragment_main, container, false)
           var bundle = Bundle()
          bundle.putString("user","Bliss")
          bundle.putInt("age",30)
     Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_secondFragment,bundle)
//        方法二 Navigation.createNavigateOnClickListener(R.id.action_mainFragment_to_secondFragment)

添加页面切换动画

创建动画文件,官网上也有此标准文件,页面切换动画 在这里插入图片描述

slide_in_left文件

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="-50%p" android:toXDelta="0"
        android:duration="@android:integer/config_mediumAnimTime"/>
    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
        android:duration="@android:integer/config_mediumAnimTime" />
</set>

slide_in_right文件

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="50%p" android:toXDelta="0"
        android:duration="@android:integer/config_mediumAnimTime"/>
    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
        android:duration="@android:integer/config_mediumAnimTime" />
</set>

slide_out_left文件

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="-50%p"
        android:duration="@android:integer/config_mediumAnimTime"/>
    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
        android:duration="@android:integer/config_mediumAnimTime" />
</set>

slide_out_right文件

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="50%p"
        android:duration="@android:integer/config_mediumAnimTime"/>
    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
        android:duration="@android:integer/config_mediumAnimTime" />
</set>

引入动画 在这里插入图片描述 在这里插入图片描述

<fragment
        android:id="@+id/mainFragment"
        android:name="com.bliss.yang.jetapp.MainFragment"
        android:label="fragment_main"
        tools:layout="@layout/fragment_main">
        <action
            android:id="@+id/action_mainFragment_to_secondFragment"
            app:destination="@id/secondFragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right" />

使用safe args插件传参

依赖

  classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.3"//safe-args插件传参数
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'androidx.navigation.safeargs' // app的build.gradle中引入添加的依赖
}

传参

 var bundle = MainFragmentArgs.Builder()
                .setUser("Bliss91")
                .setAge(31).build().toBundle()
            Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_secondFragment,bundle)

接受参数

  if(bundle!=null){
            var user = MainFragmentArgs.fromBundle(bundle).user
            var age = MainFragmentArgs.fromBundle(bundle).age
            Log.e(TAG, "safe-args接收参数:$user,$age " )
        }

在这里插入图片描述

 <fragment
        android:id="@+id/mainFragment"
        android:name="com.bliss.yang.jetapp.MainFragment"
        android:label="fragment_main"
        tools:layout="@layout/fragment_main">
        <action
            android:id="@+id/action_mainFragment_to_secondFragment"
            app:destination="@id/secondFragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right" />
        <argument
            android:name="user"
            app:argType="string"
            android:defaultValue="" />
        <argument
            android:name="age"
            app:argType="integer"
            android:defaultValue="0" />
    </fragment>

NavigationUI的使用

使类似于APP bar中的按钮和菜单与导航页面关联起来 app bar menu menu_setting

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!--  此处的id要和nav_graph中的保持一致-->
  <item
      android:id="@+id/secondFragment"
      android:icon="@drawable/ic_launcher_foreground"
      android:title="设置">

  </item>
</menu>

在这里插入图片描述

activity中实例化菜单栏


    //添加菜单栏
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        super.onCreateOptionsMenu(menu)
        menuInflater.inflate(R.menu.menu_setting,menu)
        return true
    }

处理跳转逻辑

private var appBarConfiguration:AppBarConfiguration?=null//用于APPBar的配置
    private var navController:NavController?=null//用于页面的导航和切换


    navController = Navigation.findNavController(this,R.id.nav_host_fragment_container)
        navController?.let { _navController ->
            appBarConfiguration = AppBarConfiguration.Builder(_navController.graph).build()
        }
        //将APPBar和navController绑定
        if (navController!=null && appBarConfiguration!=null){
            NavigationUI.setupActionBarWithNavController(this, navController!!,
                appBarConfiguration!!
            )
        }
        if (navController!=null){
            navController?.addOnDestinationChangedListener { controller, destination, arguments ->
                Log.e(TAG, "onDestinationChanged: 页面切换监听")
            }
        }
      * 通过NavigationUI完成点击跳转
     */
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (navController!=null){
            return NavigationUI.onNavDestinationSelected(item, navController!!)
        }
        return super.onOptionsItemSelected(item)
    }

    /**
     * 使用NavigationUI完成返回
     */
    override fun onSupportNavigateUp(): Boolean {
        if (navController!=null && appBarConfiguration!=null){
            return NavigationUI.navigateUp(navController!!, appBarConfiguration!!)
        }
        return super.onSupportNavigateUp()
    }

由于menu是写在activity中,所以第二个fragment中清除一下menu区别效果

   override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        menu.clear()//清除父容器activity中的menu,
        super.onCreateOptionsMenu(menu, inflater)
    }

示例代码地址-navigation分支