Android Jetpack的导航组件(Navigation组件)的使用

Posted 怪兽N

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack的导航组件(Navigation组件)的使用相关的知识,希望对你有一定的参考价值。

简介

导航是指支持用户导航、进入和退出应用中不同内容片段的交互。android Jetpack 的导航组件可帮助您实现导航,无论是简单的按钮点击,还是应用栏和抽屉式导航栏等更为复杂的模式,该组件均可应对。其实最最重要的是,使页面跳转管理变得非常方便。底层原理还是FragmentManager管理,Navigation组件封装了一层。

导航组件由以下三个关键部分组成:

  • 导航图:在一个集中位置包含所有导航相关信息的 XML 资源。这包括应用内所有单个内容区域(称为目标)以及用户可以通过应用获取的可能路径。
  • NavHost:显示导航图中目标的空白容器。导航组件包含一个默认 NavHost 实现 (NavHostFragment),可显示 Fragment 目标。
  • NavController:在 NavHost 中管理应用导航的对象。当用户在整个应用中移动时,NavController 会安排 NavHost 中目标内容的交换。

对于刚刚接触Navigation组件,我们常常明白的点主要有三点:

  • 怎么找到NavController

  • 怎么跳转

  • xml里写是啥

怎么找到NavController

说明之前,首先上xml

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_home_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:tag="navi_host_tag"
        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/user_navi" />

从FragmentContainerView中找到NaviController:

1 通过NavHostFragment本身

Fragment navHostFragment = getSupportFragmentManager().findFragmentById(binding.navHomeFragment.getId());
//或者navHostFragment = getSupportFragmentManager().findFragmentByTag(“navi_host_tag”);
  if(navHostFragment instanceof NavHostFragment){
    NavHostFragment navHost = (NavHostFragment) this.navHostFragment;
    NavController navController = navHost.getNavController();
    navController.navigate(R.id.register);
  }

2 因为NaviController是通过view.setTag(key,value)记录下来的,所以也可以

Object tag = binding.navHomeFragment.getTag(R.id.nav_controller_view_tag);
  if(tag instanceof NavController){
       Log.d(TAG, "onResume: ");
   }

3 直接使用Navigation.findNavController(id)

NavController navController = Navigation.findNavController(this, binding.navHomeFragment.getId());

4 直接使用Navigation.findNavController(view)

NavController navController = Navigation.findNavController(binding.navHomeFragment);
//或者
NavController navController = Navigation.findNavController(binding.navHomeFragment.someChildView);

这里要说明一下,

方法1 原理是NavHostFragment实现了NavHost,所以可以直接getController
方法2 3 4 NaviController是通过view.setTag(key,value)记录下来的,其实Navigation.find的方法都是通过tag,往parent方向查找,所以通过子View或者id都可以找到导航图的Controller

导航图的定义

下面是一个模板

<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"
            app:startDestination="@+id/title_screen">
    		...
    	    <fragment
            android:id="@+id/register"
            android:name="com.example.android.navigationsample.Register"
            android:label="fragment_register"
            tools:layout="@layout/fragment_register">
                <action
                    android:id="@+id/action_register_to_match"
                    app:destination="@id/match"
                    app:popEnterAnim="@anim/slide_in_left"
                    app:popExitAnim="@anim/slide_out_right"
                    app:enterAnim="@anim/slide_in_right"
                    app:exitAnim="@anim/slide_out_left"/>
                 <action
                        ...
                        />
                <argument android:name="userName"
         				  android:defaultValue="name"/>
                <deepLink app:uri="www.example.com/user/{userName}" />
    		</fragment>
    
    		<fragment>
                ...
    		</fragment>
    		...
</navigation> 

其中action标签的含义如下

<action
	app:destination="@id/leaderboard" //导航到目的地
	app:popUpTo="@id/title_screen"//先弹出到哪里,这个动作在目的地前
	app:popUpToInclusive="true"//是否也弹出控制的本身也弹出
	app:popEnterAnim="@anim/slide_in_left"//弹出时进入动作
	app:popExitAnim="@anim/slide_out_right"//弹出时退出动作
	app:enterAnim="@anim/slide_in_left"//进入动作
	app:exitAnim="@anim/slide_out_right"//退出动作
	/>

fragment中的数据传输

<argument android:name="userName"
         android:defaultValue="name"/>

deepLink 的deeplink

<deepLink app:uri="www.example.com/user/{userName}" />

深连接要在AndroidManifest.xml中activity标签中添加nav-graph

<activity android:name="com.example.android.navigationsample.MainActivity">
	<intent-filter>
		<action android:name="android.intent.action.MAIN" />

		<category android:name="android.intent.category.LAUNCHER" />
	</intent-filter>
	<!-- This is added to handle a deep link -->
	<nav-graph android:value="@navigation/navigation" />
</activity>

怎么跳转

这个主要有navigation(resId)、navigateUp()、popBackStack(destinationId, inclusive)

1 **navigation(resId)**这个方法最常用,其中resId既可以是navigation.xml里的fragment的resId也可以是action的resId。action标签的resId可以很丰富。

另外,navigation(…)还可以指定很多种类的参数,可以根据需要使用。

对于以下标签

    <fragment
        android:id="@+id/login_in"
        android:name="com.lqbs.gyso.view.LoginFragment"
        android:label="fragment_login"
        tools:layout="@layout/fragment_login" >
        <action
            android:id="@+id/nav_go_register"
            app:destination="@+id/register"/>
    </fragment>

可以

  NavController navController = Navigation.findNavController(binding.navHomeFragment);
  navController.navigate(R.id.nav_go_register);

  NavController navController = Navigation.findNavController(binding.navHomeFragment);
  navController.navigate(R.id.login_in);

其他的navigation函数如下
在这里插入图片描述

2 **popBackStack(destinationId, inclusive)**出栈到指定id,inclusive如果是true则destinationId这个对象也弹出,也就是弹出到destinationId的前一个。通过下面的操作可以返回到打开登录界面的界面

  NavController navController = Navigation.findNavController(binding.navHomeFragment);
  navController.popBackStack(R.id.login_in, true);

源码中可以看到,直接从栈中删除了

NavBackStackEntry entry = mBackStack.removeLast();

3 **navigateUp()**可以说的我们常见的返回,与popBackStack很相似,但是navigateUp处理了深连接。即处理了与其他应用之间的跳转连接。一般在返回键一般使用navigateUp而不用popBackStack

  NavController navController = Navigation.findNavController(binding.navHomeFragment);
  navController.navigateUp()

总结

Navigation组件就是为了方便我们管理我们的界面跳转的,有三个工作要做,找到NaviController, 定义跳转的属性,跳转。跳转往前,我们指定目的地;返回,我们指定返回到哪。

以上是关于Android Jetpack的导航组件(Navigation组件)的使用的主要内容,如果未能解决你的问题,请参考以下文章

Android Jetpack的导航组件(Navigation组件)的使用

使用 Jetpack 的 Android 导航组件销毁/重新创建的片段

是否可以使用 Android 导航架构组件(Android Jetpack)有条件地设置 startDestination?

踩坑!Android Jetpack组件间库之Navigation

Android Jetpack导航组件——Navigation的使用

android jetpack 导航仪器测试在返回导航上失败