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")

 

 

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