Navigation组件使用入门

导航组件 官方文档:https://developer.android.google.cn/guide/navigation?hl=zh_cn

一、设置环境

在应用的build.gradle文件中添加以下依赖

 dependencies {
      def nav_version = "2.3.0-alpha01"

      // Java language implementation
      implementation "androidx.navigation:navigation-fragment:$nav_version"
      implementation "androidx.navigation:navigation-ui:$nav_version"

      // Kotlin
      implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
      implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

      // Dynamic Feature Module Support
      implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"

      // Testing Navigation
      androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
    }
    

注意:如果您要在 Android Studio 中使用 Navigation 组件,则必须使用 Android Studio 3.3 或更高版本

 

二、使用

2.1 创建导航图

导航发生在应用中的各个目的地(即您的应用中用户可以导航到的任意位置)之间。这些目的地是通过操作连接的。

导航图是一种资源文件,其中包含您的所有目的地和操作。该图表会显示应用的所有导航路径。

  1. “目的地”是指应用中的不同内容区域。
  2. “操作”是指目的地之间的逻辑连接,表示用户可以采取的路径。

要向项目添加导航图,请执行以下操作:

  1. 在“Project”窗口中,右键点击 res 目录,然后依次选择 New > Android Resource File。此时系统会显示 New Resource File 对话框。
  2. 在 File name 字段中输入名称,例如“login_navigation”。
  3. 从 Resource type 下拉列表中选择 Navigation,然后点击 OK。

当您添加首个导航图时,Android Studio 会在 res 目录内创建一个 navigation 资源目录。该目录包含您的导航图资源文件(例如 nav_graph.xml)。

2.2 Navigation Editor

添加图表后,Android Studio 会在 Navigation Editor 中打开该图表。在 Navigation Editor 中,您可以直观地修改导航图,或直接修改底层 XML。

  1. Destinations panel:列出了导航宿主和目前位于 Graph Editor 中的所有目的地。
  2. Graph Editor:包含导航图的视觉表示形式。您可以在 Design 视图和 Text 视图中的底层 XML 表示形式之间切换。
  3. Attributes:显示导航图中当前所选项的属性。

点击split 查看xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto" 
        android:id="@+id/login_navigation">

</navigation>

<navigation> 元素是导航图的根元素。当您向图表添加目的地和连接操作时,可以看到相应的 <destination> 和 <action> 元素在此处显示为子元素。如果您有嵌套图表,它们将显示为子 <navigation> 元素。

2.3 向Activity添加NavHost

导航宿主是 Navigation 组件的核心部分之一。导航宿主是一个空容器,用户在您的应用中导航时,目的地会在该容器中交换进出。

导航宿主必须派生于 NavHost。Navigation 组件的默认 NavHost 实现 (NavHostFragment) 负责处理 Fragment 目的地的交换。

注意:Navigation 组件旨在用于具有一个主 Activity 和多个 Fragment 目的地的应用。主 Activity 与导航图相关联,且包含一个负责根据需要交换目的地的 NavHostFragment。在具有多个 Activity 目的地的应用中,每个 Activity 均拥有其自己的导航图。

通过 XML 添加 NavHostFragment

以下 XML 示例显示了作为应用主 Activity 一部分的 NavHostFragment

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.LoginActivity">

    <fragment
            android:id="@+id/my_nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/login_navigation"></fragment>
</androidx.constraintlayout.widget.ConstraintLayout>

请注意以下几点:

  • android:name :包含 NavHost 实现的类名称,这是一个用于放置管理 destination 的空视图。
  • app:navGraph :将 NavHostFragment 与导航图相关联。导航图会在此 NavHostFragment 中指定用户可以导航到的所有目的地。
  • app:defaultNavHost="true" 属性确保您的 NavHostFragment 会拦截系统返回按钮。请注意,只能有一个默认 NavHost。如果同一布局(例如,双窗格布局)中有多个主机,请务必仅指定一个默认 NavHost。

2.4 向导航图添加destination

您可以从现有的 Fragment 或 Activity 创建目的地。您还可以使用 Navigation Editor 创建新目的地,或创建占位符以便稍后替换为 Fragment 或 Activity。

在本示例中,我们来创建一个新目的地。要使用 Navigation Editor 添加新目的地,请执行以下操作:

  1. 在 Navigation Editor 中,点击 New Destination 图标 ,然后点击 Create new destination(也可以从下拉列表里把已经创建的fragment直接添加为目的地)。
  2. 在随即显示的 New Android Component 对话框中,创建您的 Fragment。如需详细了解 Fragment,请参阅 Fragment 文档

当您返回到 Navigation Editor 中时,会发现 Android Studio 已将此目的地添加到图表中。

2.5 destination详解

点击一个目的地以将其选中,并注意 Attributes 面板中显示的以下属性:

  • Type 字段指示在您的源代码中,该目的地是作为 Fragment、Activity 还是其他自定义类实现的。
  • Label 字段包含该目的地的 XML 布局文件的名称。
  • ID 字段包含该目的地的 ID,它用于在代码中引用该目的地。
  • Class 下拉列表显示与该目的地相关联的类的名称。您可以点击此下拉列表,将相关联的类更改为其他destination类型。

点击 Text 标签页可查看导航图的 XML 视图。XML 中同样包含该目的地的 id、name、label 和 layout 属性,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<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/login_navigation"
        app:startDestination="@id/welcomeFragment">


    <fragment
            android:id="@+id/welcomeFragment"
            android:name="com.gozap.jetpack.ui.fragment.WelcomeFragment"
            tools:layout="@layout/fragment_welcome"
            android:label="WelcomeFragment" />

    <fragment
            android:id="@+id/loginFragment"
            android:name="com.gozap.jetpack.ui.fragment.LoginFragment"
            tools:layout="@layout/fragment_login"
            android:label="LoginFragment" />
    <fragment
            android:id="@+id/registerFragment"
            android:name="com.gozap.jetpack.ui.fragment.RegisterFragment"
            tools:layout="@layout/fragment_register"
            android:label="RegisterFragment" />
</navigation>

2.6 将某个屏幕指定位startDestination

起始目的地是用户打开您的应用时看到的第一个屏幕,也是用户退出您的应用时看到的最后一个屏幕。Navigation Editor 使用房子图标 来表示起始目的地。

所有目的地就绪后,您便可以选择startDestination,实现方法如下:

1、<navigation ...  app:startDestination="@id/welcomeFragment"  > </navigation>

2、在 Design 标签页中,点击相应destination,使其突出显示,再点击导航的图标。

2.7 连接destination

操作是指目的地之间的逻辑连接。操作在导航图中以箭头表示。操作通常会将一个destination连接到另一个destination,不过您也可以创建全局操作,此类操作可让您从应用中的任意位置转到特定destination。

借助操作,您可以表示用户在您的应用中导航时可以采取的不同路径。请注意,要实际导航到各个目的地,您仍然需要编写代码来执行导航操作。如需了解详情,请参阅本主题后面的导航到目的地部分。

您可以使用 Navigation Editor 将两个目的地连接起来,具体操作步骤如下:

  1. 在 Design 标签页中,将鼠标悬停在您希望用户从中导航出来的目的地的右侧。该目的地右侧上方会显示一个圆圈,如图 4 所示。
  2. 点击您希望用户导航到的目的地,并将光标拖动到该目的地的上方,然后松开。这两个目的地之间生成的线条表示操作,如图 5 所示。
图5:通过操作连接目的地​​​​​​
图4​​​:一个包含操作连接圆圈的目的地
<?xml version="1.0" encoding="utf-8"?>
<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/login_navigation"
        app:startDestination="@id/welcomeFragment">


    <fragment
            android:id="@+id/welcomeFragment"
            android:name="com.gozap.jetpack.ui.fragment.WelcomeFragment"
            android:label="WelcomeFragment"
            tools:layout="@layout/fragment_welcome">
        <action
                android:id="@+id/action_welcomeFragment_to_loginFragment"
                app:destination="@id/loginFragment" />
        <action
                android:id="@+id/action_welcomeFragment_to_registerFragment"
                app:destination="@id/registerFragment"
                app:enterAnim="@anim/common_slide_in_right"
                app:exitAnim="@anim/common_slide_out_left"
                app:popEnterAnim="@anim/common_slide_in_left"
                app:popExitAnim="@anim/common_slide_out_right" />
    </fragment>

    <fragment
            android:id="@+id/loginFragment"
            android:name="com.gozap.jetpack.ui.fragment.LoginFragment"
            android:label="LoginFragment"
            tools:layout="@layout/fragment_login" />
    <fragment
            android:id="@+id/registerFragment"
            android:name="com.gozap.jetpack.ui.fragment.RegisterFragment"
            android:label="RegisterFragment"
            tools:layout="@layout/fragment_register" />
</navigation>

在导航图中,操作由 <action> 元素表示。操作至少应包含自己的 ID 和用户应转到的目的地的 ID。

三、 跳转与数据传递

3.1 导航到目的地

官方文档:https://developer.android.google.cn/guide/navigation/navigation-navigate?hl=zh_cn

导航到目的地是使用 NavController 完成的,后者是一个在 NavHost 中管理应用导航的对象。每个 NavHost 均有自己的相应 NavController。您可以使用以下方法之一检索 NavController

Kotlin

Java

3.1.1  使用 Safe Args 确保类型安全

要在目的地之间导航,建议使用 Safe Args Gradle 插件。该插件可以生成简单的对象和构建器类,这些类支持在目的地之间进行类型安全的导航和参数传递。

顶级build.gradle文件添加以下

 buildscript {
        repositories {
            google()
        }
        dependencies {
            def nav_version = "2.3.0-alpha01"
            classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
        }
    }

您还必须应用build.gradle 添加以下两个可用插件之一。

java:

apply plugin: "androidx.navigation.safeargs"

kotlin

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

根据迁移到 AndroidX 文档,您的 gradle.properties 文件 中必须具有 android.useAndroidX=true

启用 Safe Args 后,生成的代码会为每个操作包含以下类型安全的类和方法,以及每个发送和接收目的地。

  • 为生成操作的每一个目的地创建一个类。该类的名称是在源目的地的名称后面加上“Directions”。例如,如果源目的地是名为 WelcomeFragment的 Fragment,则生成的类的名称为 WelcomeFragmentDirections

    该类会为源目的地中定义的每个操作提供一个方法。

  • 对于用于传递参数的每个操作,都会创建一个 inner 类,该类的名称根据操作的名称确定。例如,如果操作名称为 confirmationAction,,则类名称为 ConfirmationAction。如果您的操作包含不带 defaultValue 的参数,则您可以使用关联的 action 类来设置参数值。

  • 为接收目的地创建一个类。该类的名称是在目的地的名称后面加上“Args”。例如,如果目的地 Fragment 的名称为 RegisterFragment,,则生成的类的名称为 RegisterFragmentArgs。可以使用该类的 fromBundle() 方法检索参数。

启用 Safe Args 后,该插件会生成代码,其中包含您定义的每个操作的类和方法。对于每个操作,Safe Args 还会为每个源目的地(生成相应操作的目的地)生成一个类。生成的类的名称为 "源目的地类的名称+Directions” 组成。例如,如果目的地的名称为 WelcomeFragment,则生成的类的名称为 WelcomeFragmentDirections。生成的类为源目的地中定义的每个操作提供了一个静态方法。该方法会将任何定义的操作参数作为参数,并返回可传递到 navigate() 的 NavDirections 对象。

例如,假设我们的导航图包含一个操作,该操作将源目的地 WelcomeFragment和接收目的地 LoginFragment 连接起来。

Safe Args 会生成一个 WelcomeFragmentDirections 类,其中只包含一个 action WelcomeFragmentDirectionsToLoginFragment()方法(该方法会返回 NavDirections 对象)。然后,您可以将返回的 NavDirections 对象直接传递到 navigate(),如以下示例所示:

 btn_login.setOnClickListener {
            val action = WelcomeFragmentDirections.actionWelcomeFragmentToLoginFragment()
            it.findNavController().navigate(action)
        }

3.1.2  使用Id导航

navigate(int) 接受action或目的地的资源 ID 作为参数。以下代码段展示了如何导航到 RegisterFragment

btn_register.setOnClickListener {
      
    //action id
    it.findNavController().navigate(R.id.action_welcomeFragment_to_registerFragment)

    // fragment id
    it.findNavController().navigate(R.id.registerFragment)

}

注意在使用 ID 进行导航时,我们强烈建议您尽可能使用action。action会在导航图中提供更多信息,从而直观显示目的地之间如何相互连接。通过创建action,您可以将资源 ID 替换为 Safe Args 生成的操作,从而进一步提高编译时安全性。通过使用action,您还可以在目的地之间添加动画过渡效果。如需了解详情,请参阅在目的地之间添加动画过渡效果

对于按钮,您还可以使用 Navigation 类的 createNavigateOnClickListener() 便捷方法导航到目的地,如下例所示:

(----测试未生效 ,还未找到原因----)

button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null))

3.2 为action提供导航选项

在导航图中定义操作时,Navigation 会生成相应的 NavAction 类,其中包含为该操作定义的配置,包括如下内容:

  • Destination:The resource ID of the target destination.。
  • Default argumentsandroid.os.Bundle,包含target destination的默认值(如有提供)。
  • Navigation options:表示为 NavOptions。此类包含从 target destination往返的所有特殊配置,包括动画资源配置、弹出行为以及是否应在单一顶级模式下启动目的地。

3.2.1  NavOptions

login_navigation.xml

<fragment
            android:id="@+id/welcomeFragment"
            android:name="com.gozap.jetpack.ui.fragment.WelcomeFragment"
            android:label="WelcomeFragment"
            tools:layout="@layout/fragment_welcome">
        <action
                android:id="@+id/action_welcomeFragment_to_loginFragment"
                app:destination="@id/loginFragment" />
        
        <!--设置动画参数-->
       <action
                android:id="@+id/action_welcomeFragment_to_registerFragment"
                app:destination="@id/registerFragment"
                app:enterAnim="@anim/common_slide_in_right"
                app:exitAnim="@anim/common_slide_out_left"
                app:popEnterAnim="@anim/common_slide_in_left"
                app:popExitAnim="@anim/common_slide_out_right"
                app:popUpTo="@id/registerFragment"
                app:popUpToInclusive="true"/>
</fragment>


WelcomeFragment.kt

btn_login.setOnClickListener {
            //设置动画参数
            val navOption= navOptions {
                anim {
                    enter = R.anim.common_slide_in_right
                    exit = R.anim.common_slide_out_left
                    popEnter = R.anim.common_slide_in_left
                    popExit = R.anim.common_slide_out_right
                }
            }

            val action = WelcomeFragmentDirections.actionWelcomeFragmentToLoginFragment()
            it.findNavController().navigate(action,navOption)
        }

扩充该导航图时,系统会解析这些操作,同时使用图中定义的配置生成相应的 NavAction 对象。例如,action_welcomeFragment_to_registerFragment 定义为从目的地 welcomeFragment 到目的地 registerFragment 的导航。该操作包含动画以及 popTo 行为,该行为会从返回堆栈中移除所有目的地。所有这些设置都会以 NavOptions 形式捕获并连接到 NavAction

要遵循此 NavAction,请使用 NavController.navigate()(传递action ID,不能使用destination ID ),否则无效

3.3 数据传递

官方文档:https://developer.android.google.cn/guide/navigation/navigation-pass-data?hl=zh_cn

定义destination arguments

在Navigation Editor中点击接收参数的descination  添加参数信息

xml代码如下:

 <fragment
            android:id="@+id/registerFragment"
            android:name="com.jetpack.ui.fragment.RegisterFragment"
            android:label="RegisterFragment"
            tools:layout="@layout/fragment_register">
        <argument
                android:name="EMAIL"
                android:defaultValue="[email protected]"
                app:argType="string" />
    </fragment>

3.3.1 使用 Safe Args 传递安全的数据

WelcomeFragment 中设置参数:

        btn_register.setOnClickListener {
            val action = WelcomeFragmentDirections
                           .actionWelcomeToRegister("[email protected]")
            findNavController().navigate(action)
        }

RegisterFragment中接收参数:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val safeArgs: RegisterFragmentArgs by navArgs()
        val email = safeArgs.EMAIL
    }

3.3.2 使用Bundle对象传递参数

WelcomeFragment中设置参数:

        btn_register.setOnClickListener {
            var bundle = bundleOf("EMAIL" to "[email protected]")
            findNavController().navigate(R.id.action_welcome_to_register, bundle)
        }

RegisterFragment中接收参数:

 arguments?.getString("EMAIL")

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章