(六、3)使用導(dǎo)航架構(gòu)組件實(shí)現(xiàn)導(dǎo)航

導(dǎo)航架構(gòu)組件簡(jiǎn)化了應(yīng)用中目標(biāo)之間導(dǎo)航的實(shí)現(xiàn)。 一組目的地組成應(yīng)用程序的導(dǎo)航圖。

目的地是您可以在應(yīng)用中導(dǎo)航到的任何位置。 雖然目標(biāo)通常是代表特定屏幕的片段,但導(dǎo)航架構(gòu)組件支持其他目標(biāo)類型:

  • 活動(dòng)。
  • 導(dǎo)航圖和子圖 - 當(dāng)目標(biāo)是圖形或子圖時(shí),導(dǎo)航到該圖或子圖的起始目標(biāo)。
  • 自定義目標(biāo)類型。

除目標(biāo)之外,導(dǎo)航圖還在稱為操作的目標(biāo)之間建立連接。 圖1顯示了一個(gè)示例應(yīng)用程序的導(dǎo)航圖的直觀表示,該應(yīng)用程序包含由5個(gè)操作連接的6個(gè)目標(biāo)。
圖1.導(dǎo)航圖

導(dǎo)航架構(gòu)組件基于導(dǎo)航原理實(shí)現(xiàn)。

注意:如果要在Android Studio中使用導(dǎo)航架構(gòu)組件,則必須使用Android Studio 3.2 Canary 14或更高版本。

一、在項(xiàng)目中設(shè)置導(dǎo)航

在創(chuàng)建導(dǎo)航圖之前,必須為項(xiàng)目設(shè)置導(dǎo)航架構(gòu)組件。 要在Android Studio中設(shè)置項(xiàng)目,請(qǐng)執(zhí)行以下步驟。

  1. 如果使用Beta,Release Candidate或Stable構(gòu)建,則必須啟用導(dǎo)航編輯器。 單擊文件>設(shè)置(Mac上的Android Studio>首選項(xiàng)),在左窗格中選擇實(shí)驗(yàn)類別,選中啟用導(dǎo)航編輯器,然后重新啟動(dòng)Android Studio。
  2. 將以下導(dǎo)航架構(gòu)組件添加到您的應(yīng)用程序或模塊的build.gradle文件中。
  3. 在“項(xiàng)目”窗口中,右鍵單擊res目錄,然后選擇“新建”>“Android資源文件”。 出現(xiàn)“新建資源文件”對(duì)話框。
  4. 在“文件名”字段中鍵入名稱,例如“nav_graph”。
  5. 從“資源類型”下拉列表中選擇“導(dǎo)航”。
  6. 單擊確定。 發(fā)生以下情況:
    a. 在res目錄中創(chuàng)建導(dǎo)航資源目錄。
    b. 在導(dǎo)航目錄中創(chuàng)建nav_graph.xml文件。
    c. nav_graph.xml文件在導(dǎo)航編輯器中打開。 此xml文件包含導(dǎo)航圖。
  7. 單擊“文本”選項(xiàng)卡以切換到XML文本視圖。 空導(dǎo)航圖的XML如下所示:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android">
</navigation>
  1. 單擊“設(shè)計(jì)”返回“導(dǎo)航編輯器”。

二、瀏覽導(dǎo)航編輯器

在導(dǎo)航編輯器中,您可以快速構(gòu)建導(dǎo)航圖,而不是手動(dòng)構(gòu)建圖形的XML。 如圖2所示,導(dǎo)航編輯器有三個(gè)部分:


圖2.導(dǎo)航編輯器

導(dǎo)航編輯器的部分是:

  1. “目標(biāo)”列表 - 列出“曲線圖編輯器”中當(dāng)前的所有目標(biāo)。
  2. 圖表編輯器 - 包含導(dǎo)航圖的可視化表示。
  3. 屬性編輯器 - 包含與導(dǎo)航圖中的目標(biāo)和操作關(guān)聯(lián)的屬性。

三、確定目的地

創(chuàng)建導(dǎo)航圖的第一步是確定應(yīng)用的目的地。 您可以從現(xiàn)有項(xiàng)目中的片段和活動(dòng)創(chuàng)建空白目標(biāo)或創(chuàng)建目標(biāo)。

注意:導(dǎo)航體系結(jié)構(gòu)組件專為具有一個(gè)具有多個(gè)片段目標(biāo)的主要活動(dòng)的應(yīng)用程序而設(shè)計(jì)。 主要活動(dòng)“托管”導(dǎo)航圖。 在具有多個(gè)活動(dòng)目標(biāo)的應(yīng)用中,每個(gè)附加活動(dòng)都會(huì)托管自己的導(dǎo)航圖。 修改主機(jī)導(dǎo)航活動(dòng)將在本文檔的后面部分討論。

要確定應(yīng)用的目標(biāo),請(qǐng)使用以下步驟。

  1. 在“曲線圖編輯器”中,單擊“New Destination” 出現(xiàn)“New Destination”對(duì)話框。

  2. 單擊“Create blank destination”或單擊片段或活動(dòng)。 將出現(xiàn)“新建Android組件”對(duì)話框。

  3. 在“片段名稱”字段中輸入名稱。 此名稱是片段類的名稱。

  4. 在“片段布局名稱”字段中輸入名稱。 此名稱是片段的布局文件的名稱。

  5. 單擊完成。 表示目標(biāo)的框顯示在“曲線圖編輯器”和“目標(biāo)”列表中。 發(fā)生以下情況:

  • 如果您創(chuàng)建了空白目標(biāo),則“圖表編輯器”會(huì)在目標(biāo)中顯示消息“Hello blank fragment”。 如果單擊片段或活動(dòng),則“圖表編輯器”將顯示該活動(dòng)或片段的布局預(yù)覽。
  • 為您的項(xiàng)目創(chuàng)建Fragment子類。 此類具有您在步驟3中指定的名稱。
  • 為您的項(xiàng)目創(chuàng)建資源文件。 此文件具有您在步驟4中指定的名稱。

圖3顯示了一個(gè)空白和一個(gè)現(xiàn)有目的地。


圖3. Graph Editor中的新目標(biāo)和現(xiàn)有目標(biāo)
  1. 單擊新插入的目標(biāo)以突出顯示目標(biāo)。 “屬性”面板中顯示以下屬性:
  • 類型”字段包含“片段”或“活動(dòng)”,以指示目標(biāo)是否在源代碼中實(shí)現(xiàn)為片段或活動(dòng)。
  • Label字段包含目標(biāo)的XML布局文件的名稱。
  • ID字段包含將用于在代碼中引用目標(biāo)的目標(biāo)ID。
  • Class字段包含目標(biāo)類的名稱。
  1. 單擊“文本”選項(xiàng)卡以切換到XML視圖。 XML現(xiàn)在包含基于現(xiàn)有類和布局文件的名稱的id,名稱(類名),標(biāo)簽和布局屬性:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    app:startDestination="@id/blankFragment">
    <fragment
        android:id="@+id/blankFragment"
        android:name="com.example.cashdog.cashdog.BlankFragment"
        android:label="Blank"
        tools:layout="@layout/fragment_blank" />
</navigation>

注意:XML有一個(gè)startDestination屬性,指向新空目標(biāo)的id(app:startDestination =“@ + id / fragment”)。 有關(guān)起始目的地的更多信息,請(qǐng)參閱指定屏幕作為起始目的地。

四、連接目的地

您必須有多個(gè)目標(biāo)才能連接目標(biāo)。 以下是包含兩個(gè)空白目標(biāo)的導(dǎo)航圖的XML:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    app:startDestination="@id/blankFragment">
    <fragment
        android:id="@+id/blankFragment"
        android:name="com.example.cashdog.cashdog.BlankFragment"
        android:label="fragment_blank"
        tools:layout="@layout/fragment_blank" />
    <fragment
        android:id="@+id/blankFragment2"
        android:name="com.example.cashdog.cashdog.BlankFragment2"
        android:label="Blank2"
        tools:layout="@layout/fragment_blank_fragment2" />
</navigation>

目的地使用動(dòng)作連接。 連接兩個(gè)目的地:

  1. 在圖表編輯器中,將鼠標(biāo)懸停在您希望用戶導(dǎo)航的目標(biāo)的右側(cè)。 目的地上會(huì)出現(xiàn)一個(gè)圓圈。


    圖4.動(dòng)作連接圈
  2. 單擊并按住,將光標(biāo)拖動(dòng)到希望用戶導(dǎo)航到的目標(biāo)上,然后釋放。 繪制一條線以指示兩個(gè)目的地之間的導(dǎo)航。


    圖5.連接的目的地
  3. 單擊箭頭以突出顯示該操作。 “屬性”面板中顯示以下屬性:

  • “類型”字段包含“操作”。
  • ID字段包含系統(tǒng)為操作分配的ID。
  • Destination字段包含目標(biāo)片段或活動(dòng)的ID。
  1. 單擊“文本”選項(xiàng)卡以切換到XML視圖。 已將一個(gè)操作元素添加到父目標(biāo)。 該操作具有系統(tǒng)分配的ID和目標(biāo)屬性,其中包含下一個(gè)目標(biāo)的ID。 例如:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    app:startDestination="@id/blankFragment">
    <fragment
        android:id="@+id/blankFragment"
        android:name="com.example.cashdog.cashdog.BlankFragment"
        android:label="fragment_blank"
        tools:layout="@layout/fragment_blank" >
        <action
            android:id="@+id/action_blankFragment_to_blankFragment2"
            app:destination="@id/blankFragment2" />
    </fragment>
    <fragment
        android:id="@+id/blankFragment2"
        android:name="com.example.cashdog.cashdog.BlankFragment2"
        android:label="fragment_blank_fragment2"
        tools:layout="@layout/fragment_blank_fragment2" />
</navigation>

五、將屏幕指定為起始目的地

圖表編輯器在應(yīng)用程序的第一個(gè)目標(biāo)名稱旁邊放置一個(gè)房屋圖標(biāo)。 此圖標(biāo)表示這是導(dǎo)航圖中的起始目標(biāo)。 您可以使用以下步驟將另一個(gè)目標(biāo)指定為起始目標(biāo):

  1. 從圖表編輯器中,單擊目標(biāo)。 目的地突出顯示。
  2. 單擊“屬性”面板中的“設(shè)置起始目標(biāo)”。 目的地現(xiàn)在是起始目的地。

六、修改活動(dòng)以主持導(dǎo)航

活動(dòng)通過實(shí)施添加到活動(dòng)布局的NavHost界面來托管應(yīng)用程序的導(dǎo)航。 NavHost是一個(gè)空視圖,當(dāng)用戶瀏覽您的應(yīng)用程序時(shí),目的地會(huì)被換入和換出。

Navigation Architecture Component的默認(rèn)NavHost實(shí)現(xiàn)是NavHostFragment。

包含NavHost后,必須使用navGraph屬性將導(dǎo)航圖與NavHostFragment相關(guān)聯(lián)。 以下代碼段顯示了如何在活動(dòng)的布局文件中包含NavHostFragment并將導(dǎo)航圖與NavHostFragment相關(guān)聯(lián):

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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=".MainActivity">

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

</android.support.constraint.ConstraintLayout>

上一個(gè)示例包含一個(gè)app:defaultNavHost =“true”屬性。 此屬性可確保您的NavHostFragment攔截系統(tǒng)“后退”按鈕。 您還將覆蓋AppCompatActivity.onSupportNavigateUp()并調(diào)用NavController.navigateUp,如下所示:

@Override
public boolean onSupportNavigateUp() {
    return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp();
}
以編程方式創(chuàng)建NavHostFragment

您還可以使用NavHostFragment.create()以編程方式創(chuàng)建具有特定圖形資源的NavHostFragment,如下例所示:

NavHostFragment finalHost = NavHostFragment.create(R.navigation.example_graph);
getSupportFragmentManager().beginTransaction()
    .replace(R.id.nav_host, finalHost)
    .setPrimaryNavigationFragment(finalHost) // this is the equivalent to app:defaultNavHost="true"
    .commit();

七、將目標(biāo)綁定到UI小部件

使用NavController類導(dǎo)航到目標(biāo)。 可以使用以下靜態(tài)方法之一檢索NavController:

  • NavHostFragment.findNavController(Fragment)
  • Navigation.findNavController(Activity, @IdRes int viewId)
  • Navigation.findNavController(View)

檢索NavController后,使用其navigate()方法導(dǎo)航到目標(biāo)。 navigate()方法接受資源ID。 ID可以是導(dǎo)航圖或操作中特定目標(biāo)的ID。 使用操作的ID而不是目標(biāo)的資源ID具有優(yōu)勢(shì),例如將過渡與導(dǎo)航相關(guān)聯(lián)。
以下代碼段顯示了如何導(dǎo)航到ViewTransactionsFragment:

viewTransactionsButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Navigation.findNavController(view).navigate(R.id.viewTransactionsAction);
    }
});

Android系統(tǒng)維護(hù)一個(gè)包含最后訪問目的地的后棧。 當(dāng)用戶打開應(yīng)用程序時(shí),應(yīng)用程序的第一個(gè)目標(biāo)位于堆棧中。 每次調(diào)用navigate()方法都會(huì)將另一個(gè)目標(biāo)放在堆棧頂部。 相反,按向上或向后按鈕分別調(diào)用NavController.navigateUp()NavController.popBackStack()方法,以從堆棧中彈出頂部目標(biāo)。

對(duì)于按鈕,您還可以使用Navigation類的createNavigateOnClickListener()便捷方法導(dǎo)航到目標(biāo):

button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));
將目標(biāo)綁定到菜單驅(qū)動(dòng)的UI組件

您可以使用目標(biāo)的id作為XML中導(dǎo)航抽屜或溢出菜單項(xiàng)的相同ID,將目標(biāo)綁定到導(dǎo)航抽屜和溢出菜單。 以下代碼段顯示了詳細(xì)信息屏幕目標(biāo),其ID為details_page_fragment:

<fragment android:id="@+id/details_page_fragment"
     android:label="@string/details"
     android:name="com.example.android.myapp.DetailsFragment" />

對(duì)目的地和菜單項(xiàng)使用相同的ID會(huì)自動(dòng)將目的地與菜單項(xiàng)相關(guān)聯(lián)。 以下XML顯示了如何將片段目標(biāo)與導(dǎo)航抽屜中的菜單項(xiàng)相關(guān)聯(lián)(例如,menu_nav_drawer.xml):

<item
    android:id="@id/details_page_fragment"
    android:icon="@drawable/ic_details"
    android:title="@string/details" />

以下XML顯示了如何將詳細(xì)信息目標(biāo)綁定到溢出菜單(例如menu_overflow.xml):

<item
    android:id="@id/details_page_fragment"
    android:icon="@drawable/ic_details"
    android:title="@string/details"
    android:menuCategory:"secondary" />

導(dǎo)航架構(gòu)組件包括NavigationUI類。 此類有幾個(gè)靜態(tài)方法,您可以使用帶有導(dǎo)航目標(biāo)的連接菜單項(xiàng)。 例如,以下代碼顯示如何使用setupWithNavController()方法將菜單抽屜中的項(xiàng)目連接到NavigationView:

NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
NavigationUI.setupWithNavController(navigationView, navController);

必須使用這些NavigationUI方法設(shè)置菜單驅(qū)動(dòng)的導(dǎo)航組件,以便這些UI元素的狀態(tài)與NavController的更改保持同步。

八、在目的地之間傳遞數(shù)據(jù)

您可以通過兩種方式在目標(biāo)之間傳遞數(shù)據(jù):使用Bundle對(duì)象或使用安全標(biāo)記Gradle插件以類型安全的方式傳遞數(shù)據(jù)。 使用以下步驟使用Bundle對(duì)象在目標(biāo)之間傳遞數(shù)據(jù)。 如果您使用的是Gradle,請(qǐng)考慮按照類型安全的方式在目標(biāo)之間傳遞數(shù)據(jù)中的說明。

  1. 在圖表編輯器中,單擊接收參數(shù)的目標(biāo)位置。 目的地亮點(diǎn)。
  2. 單擊“屬性”面板的“參數(shù)”部分中的“添加”(+)。 出現(xiàn)空名稱和默認(rèn)值字段。
  3. 雙擊名稱并輸入?yún)?shù)的名稱。
  4. 按Tab鍵并輸入?yún)?shù)的默認(rèn)值。
  5. 單擊此目標(biāo)之前的操作。 參數(shù)默認(rèn)值應(yīng)包含新添加的參數(shù)。
  6. 單擊“文本”選項(xiàng)卡以切換到XML視圖。 帶有name和defaultValue屬性的參數(shù)元素已添加到目標(biāo):
<fragment
   android:id="@+id/confirmationFragment"
   android:name="com.example.cashdog.cashdog.ConfirmationFragment"
   android:label="fragment_confirmation"
   tools:layout="@layout/fragment_confirmation">
   <argument android:name="amount" android:defaultValue=”0” />
  1. 在您的代碼中,使用navigate()方法創(chuàng)建一個(gè)包并將其傳遞到目標(biāo):
Bundle bundle = new Bundle();
bundle.putString("amount", amount);
Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);

在接收目標(biāo)的代碼中,使用getArguments()方法檢索包并使用其內(nèi)容:

TextView tv = view.findViewById(R.id.textViewAmount);
tv.setText(getArguments().getString("amount"));

九、添加偵聽器以處理導(dǎo)航事件

您可以使用addOnNavigatedListener()將OnNavigatedListener添加到NavController。 OnNavigatedListener在控制器導(dǎo)航到新目標(biāo)時(shí)接收事件。 您可以使用此處理程序進(jìn)行特定于目標(biāo)的更改,例如顯示或隱藏某些UI元素。

調(diào)用addOnNavigatedListener()時(shí),如果當(dāng)前目標(biāo)存在,則立即將其發(fā)送給您的偵聽器。

十、以類型安全的方式在目標(biāo)之間傳遞數(shù)據(jù)

Navigation Architecture Component有一個(gè)Gradle插件,稱為safeargs,它生成簡(jiǎn)單的對(duì)象和構(gòu)建器類,以便對(duì)目標(biāo)和操作指定的參數(shù)進(jìn)行類型安全訪問。 Safe args建立在Bundle方法的基礎(chǔ)之上,但需要一些額外的代碼來換取更多類型的安全性。 如果您使用的是Gradle,則可以使用safe args插件。 要添加此插件,請(qǐng)將“androidx.navigation.safeargs”插件添加到build.gradle文件中。 例如:

apply plugin: 'com.android.application'
apply plugin: 'androidx.navigation.safeargs'

android {
   //...
}

配置Gradle插件后,請(qǐng)按照以下步驟使用類型安全的args。

  1. 在圖表編輯器中,單擊接收參數(shù)的目標(biāo)位置。 目的地亮點(diǎn)。
  2. 單擊“屬性”面板的“參數(shù)”部分中的+。 出現(xiàn)空名稱和默認(rèn)值字段。
  3. 雙擊名稱并輸入?yún)?shù)的名稱。
  4. 按Tab鍵并從下拉列表中選擇參數(shù)的類型。
  5. 按Tab鍵并輸入?yún)?shù)的默認(rèn)值。
  6. 單擊此目標(biāo)之前的操作。 參數(shù)默認(rèn)值應(yīng)包含新添加的參數(shù)。
  7. 單擊“文本”選項(xiàng)卡以切換到XML視圖。 帶有name和defaultValue屬性的參數(shù)元素已添加到目標(biāo):
<fragment
    android:id="@+id/confirmationFragment"
    android:name="com.example.buybuddy.buybuddy.ConfirmationFragment"
    android:label="fragment_confirmation"
    tools:layout="@layout/fragment_confirmation">
    <argument android:name="amount" android:defaultValue="1" app:type="integer"/>
</fragment>

使用safeargs插件生成代碼時(shí),會(huì)為操作以及發(fā)送和接收目標(biāo)創(chuàng)建簡(jiǎn)單對(duì)象和構(gòu)建器類。 這些課程是:

  • 動(dòng)作源自的目的地的類,附加“方向”一詞。
    因此,如果原始片段標(biāo)題為SpecifyAmountFragment,則生成的類稱為SpecifyAmountFragmentDirections。 這個(gè)類有一個(gè)方法,以用于傳遞參數(shù)的動(dòng)作命名,用于捆綁參數(shù),例如confirmationAction()
  • 一個(gè)內(nèi)部類,其名稱基于用于傳遞參數(shù)的操作。 如果傳遞的操作名為confirmationAction,則該類名為ConfirmationAction。
  • 傳遞參數(shù)的目標(biāo)的類,附加單詞Args。
    因此,如果目標(biāo)片段標(biāo)題為ConfirmationFragment,則生成的類稱為ConfirmationFragmentArgs。 使用此類的fromBundle()方法來檢索參數(shù)。

以下代碼顯示如何使用這些方法設(shè)置參數(shù)并將其傳遞給navigate()方法。

@Override
public void onClick(View view) {
   EditText amountTv = (EditText) getView().findViewById(R.id.editTextAmount);
   int amount = Integer.parseInt(amountTv.getText().toString());
   ConfirmationAction action =
           SpecifyAmountFragmentDirections.confirmationAction()
   action.setAmount(amount)
   Navigation.findNavController(view).navigate(action);
}

在接收目標(biāo)的代碼中,使用getArguments()方法檢索包并使用其內(nèi)容:

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    TextView tv = view.findViewById(R.id.textViewAmount);
    int amount = ConfirmationFragmentArgs.fromBundle(getArguments()).getAmount();
    tv.setText(amount + "")
}

十一、將目標(biāo)分組為嵌套導(dǎo)航圖

可以將一系列目的地分組為導(dǎo)航圖中的子圖。 子圖稱為嵌套圖,而包含圖稱為“根圖”。嵌套圖對(duì)于組織和重用應(yīng)用程序UI的各個(gè)部分非常有用,例如單獨(dú)的登錄流程。

與根圖一樣,嵌套圖必須將目標(biāo)標(biāo)識(shí)為起始目標(biāo)。 嵌套圖形封裝了它的目的地; 嵌套圖外部的目標(biāo)(例如根圖上的目標(biāo))僅通過其起始目標(biāo)訪問嵌套圖。 圖6顯示了簡(jiǎn)單匯款應(yīng)用程序的導(dǎo)航圖。 該圖有兩個(gè)流程:允許用戶匯款的流程和允許用戶查看其余額的流程。


圖6.匯款導(dǎo)航圖

要將目標(biāo)分組到嵌套圖中:

  1. 在“曲線圖編輯器”中,按住shift并單擊要包含在嵌套圖形中的目標(biāo)。 每個(gè)目的地都突出顯示

  2. 打開上下文菜單,然后選擇“移動(dòng)到嵌套圖形”>“新建圖形”。 目標(biāo)包含在嵌套圖中。 圖7顯示了Graph Editor中的嵌套圖。


    圖4. Graph Editor中的嵌套圖
  3. 單擊嵌套圖以突出顯示它。 “屬性”面板中顯示以下屬性:

  • “類型”字段包含“嵌套圖”。
  • ID字段包含嵌套圖的系統(tǒng)分配ID。 此ID用于引用代碼中的嵌套圖。
  1. 雙擊嵌套圖。 將顯示嵌套圖中的目標(biāo)。
  2. 在“目標(biāo)”列表中,單擊“根”以返回到根導(dǎo)航圖。
  3. 單擊“文本”選項(xiàng)卡以切換到XML視圖。 圖表中添加了嵌套導(dǎo)航圖。 此導(dǎo)航圖具有自己的打開和關(guān)閉導(dǎo)航元素。 此嵌套圖的ID為sendMoneyGraph,startDestination屬性指向嵌套圖中的第一個(gè)目標(biāo)(chooseRecipient):
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   xmlns:android="http://schemas.android.com/apk/res/android"
   app:startDestination="@id/mainFragment">
   <fragment
       android:id="@+id/mainFragment"
       android:name="com.example.cashdog.cashdog.MainFragment"
       android:label="fragment_main"
       tools:layout="@layout/fragment_main" >
       <action
           android:id="@+id/action_mainFragment_to_chooseRecipient"
           app:destination="@id/sendMoneyGraph" />
       <action
           android:id="@+id/action_mainFragment_to_viewBalanceFragment"
           app:destination="@id/viewBalanceFragment" />
   </fragment>
   <fragment
       android:id="@+id/viewBalanceFragment"
       android:name="com.example.cashdog.cashdog.ViewBalanceFragment"
       android:label="fragment_view_balance"
       tools:layout="@layout/fragment_view_balance" />
   <navigation android:id="@+id/sendMoneyGraph" app:startDestination="@id/chooseRecipient">
       <fragment
           android:id="@+id/chooseRecipient"
           android:name="com.example.cashdog.cashdog.ChooseRecipient"
           android:label="fragment_choose_recipient"
           tools:layout="@layout/fragment_choose_recipient">
           <action
               android:id="@+id/action_chooseRecipient_to_chooseAmountFragment"
               app:destination="@id/chooseAmountFragment" />
       </fragment>
       <fragment
           android:id="@+id/chooseAmountFragment"
           android:name="com.example.cashdog.cashdog.ChooseAmountFragment"
           android:label="fragment_choose_amount"
           tools:layout="@layout/fragment_choose_amount" />
   </navigation>
</navigation>
  1. 在您的代碼中,將連接根圖的操作的資源ID傳遞給嵌套圖:
Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);

十二、使用<include>引用其他導(dǎo)航圖

在導(dǎo)航圖中,您可以使用&lt; include&gt;來引用其他圖表。 雖然這在功能上與使用嵌套圖相同,但&lt; include&gt; 允許您使用其他項(xiàng)目模塊或庫項(xiàng)目中的圖形,如下例所示:

<include app:graph="@navigation/included_graph"/>

<include>包含一個(gè)屬性app:graph,指向要包含的圖形資源。 不允許其他屬性。

十三、為目標(biāo)創(chuàng)建深層鏈接

在Android中,深層鏈接是指向應(yīng)用中特定目標(biāo)的URI。 當(dāng)您希望將用戶發(fā)送到特定目的地以在您的應(yīng)用中執(zhí)行某項(xiàng)任務(wù)時(shí),這些URI非常有用,例如發(fā)送資金流,允許用戶快速匯款給某人。

為目標(biāo)分配深層鏈接

要在導(dǎo)航圖中為目標(biāo)分配深層鏈接,請(qǐng)執(zhí)行以下操作:

  1. 從圖表編輯器中,選擇深層鏈接的目標(biāo)。
  2. 單擊“屬性”面板的“深層鏈接”部分中的+。 將出現(xiàn)“添加深層鏈接”對(duì)話框。
  3. 在URI字段中鍵入U(xiǎn)RI,例如“www.cashdog.com/sendmoney”,它表示應(yīng)用程序中發(fā)送貨幣嵌套圖的起始目的地。
    請(qǐng)注意以下事項(xiàng):
  • 沒有方案的URI被假定為http和https。 例如,www.cashdog.comhttp://www.cashdog.comhttps://www.cashdog.com相匹配。
  • 占位符以{placeholder_name}的形式匹配1個(gè)或多個(gè)字符。 占位符的String值在參數(shù)Bundle中可用,并帶有相同名稱的鍵。 例如,http://www.example.com/users/ {id}http://www.example.com/users/4相匹配。
  • .*通配符可用于匹配0個(gè)或多個(gè)字符。
  1. (可選)選中“自動(dòng)驗(yàn)證”以要求Google驗(yàn)證您是URI的所有者。 有關(guān)更多信息,請(qǐng)參閱驗(yàn)證Android應(yīng)用程序鏈接。
  2. 單擊添加。 所選目標(biāo)上方會(huì)顯示一個(gè)鏈接圖標(biāo),表示該目標(biāo)具有深層鏈接。
  3. 單擊“文本”選項(xiàng)卡以切換到XML視圖。 已將嵌套的深層鏈接元素添加到目標(biāo):
<deepLink app:uri="https://cashdog.com/sendmoney"/>

當(dāng)用戶使用深層鏈接目標(biāo)中的“后退”按鈕時(shí),他們會(huì)導(dǎo)航回導(dǎo)航堆棧,就像他們從應(yīng)用程序的入口點(diǎn)進(jìn)入您的應(yīng)用程序一樣。

為深層鏈接添加intent過濾器

您必須添加manifest.xml文件以在您的應(yīng)用中啟用深層鏈接:

  • 對(duì)于Android Studio 3.0和3.1,您必須手動(dòng)添加intent-filter元素。 有關(guān)更多信息,請(qǐng)參閱創(chuàng)建應(yīng)用程序內(nèi)容的深層鏈接。
  • 對(duì)于Android Studio 3.2+,您可以向活動(dòng)元素添加nav-graph元素:
<activity name=".MainActivity">
    <nav-graph android:value="@navigation/main_nav" />
</activity>

作為清單合并構(gòu)建步驟的一部分,此元素將替換為匹配導(dǎo)航圖中所有深層鏈接所需的生成的<intent-filter>元素。

以編程方式使用NavDeepLinkBuilder創(chuàng)建深層鏈接

您可以使用NavDeepLinkBuilder類構(gòu)造PendingIntent,將用戶帶到特定目標(biāo)。

觸發(fā)此深層鏈接時(shí),將清除任務(wù)后臺(tái)堆棧并替換為深層鏈接目標(biāo)。 嵌套圖形時(shí),每個(gè)嵌套級(jí)別的起始目標(biāo)(即層次結(jié)構(gòu)中每個(gè)<navigation>元素的起始目標(biāo))也會(huì)添加到堆棧中。

您可以使用NavDeepLinkBuilder(Context)直接構(gòu)造PendingIntent,如下例所示。 請(qǐng)注意,如果提供的上下文不是Activity,則構(gòu)造函數(shù)使用PackageManager.getLaunchIntentForPackage()作為要啟動(dòng)的默認(rèn)活動(dòng)(如果可用)。

PendingIntent pendingIntent = new NavDeepLinkBuilder(context)
    .setGraph(R.navigation.mobile_navigation)
    .setDestination(R.id.android)
    .setArguments(args)
    .createPendingIntent();

注意:如果您有現(xiàn)有的NavController,還可以通過NavController.createDeepLink()創(chuàng)建深層鏈接。

十四、在目的地之間創(chuàng)建過渡

導(dǎo)航架構(gòu)組件提供了在目標(biāo)之間輕松添加轉(zhuǎn)換(例如淡入和淡出)的功能。 要添加轉(zhuǎn)換:

  1. 創(chuàng)建動(dòng)畫資源文件。導(dǎo)航架構(gòu)組件支持屬性和視圖動(dòng)畫。有關(guān)更多信息,請(qǐng)參閱動(dòng)畫資源。
  2. 在“曲線圖編輯器”中,單擊應(yīng)進(jìn)行過渡的操作。
  3. 在“屬性”面板的“過渡”部分中,單擊“輸入”旁邊的向下箭頭。將顯示項(xiàng)目中的轉(zhuǎn)換列表。
  4. 選擇用戶進(jìn)入目的地時(shí)發(fā)生的轉(zhuǎn)換。
  5. 在“屬性”面板的“過渡”部分中,單擊“退出”旁邊的向下箭頭。將顯示項(xiàng)目中的轉(zhuǎn)換列表。
  6. 選擇用戶退出目標(biāo)時(shí)發(fā)生的轉(zhuǎn)換。
  7. 單擊“文本”選項(xiàng)卡以切換到XML文本視圖。轉(zhuǎn)換的XML出現(xiàn)在步驟2中指定的操作的action元素中。該操作嵌入在轉(zhuǎn)換發(fā)生之前處于活動(dòng)狀態(tài)的目標(biāo)的XML中。在以下示例中,defineAmountFragment是活動(dòng)目標(biāo),它包含具有過渡動(dòng)畫的操作:
<fragment
    android:id="@+id/specifyAmountFragment"
    android:name="com.example.buybuddy.buybuddy.SpecifyAmountFragment"
    android:label="fragment_specify_amount"
    tools:layout="@layout/fragment_specify_amount">
    <action
        android:id="@+id/confirmationAction"
        app:destination="@id/confirmationFragment"
        app:enterAnim="@anim/slide_in_right"
        app:exitAnim="@anim/slide_out_left"
        app:popEnterAnim="@anim/slide_in_left"
        app:popExitAnim="@anim/slide_out_right" />
 </fragment>

在此示例中,我們?cè)谝苿?dòng)到目標(biāo)時(shí)會(huì)發(fā)生轉(zhuǎn)換(enterAnim和exitAnim以及退出該目標(biāo)時(shí)(popEnterAnim和popExitAnim))。

在目標(biāo)之間添加共享元素轉(zhuǎn)換

除了過渡動(dòng)畫之外,導(dǎo)航架構(gòu)組件還支持在目標(biāo)之間添加共享元素過渡。

與動(dòng)畫不同,共享元素轉(zhuǎn)換是以編程方式提供的,而不是通過導(dǎo)航XML文件提供的,因?yàn)樗鼈冃枰媚M诠蚕碓剞D(zhuǎn)換中的View實(shí)例。

每種類型的目標(biāo)都通過Navigator.Extras接口的子類實(shí)現(xiàn)此編程API。 Extras被傳遞給navigate()的調(diào)用。

片段目標(biāo)共享元素轉(zhuǎn)換

FragmentNavigator.Extras類允許您將共享元素附加到對(duì)Fragment目標(biāo)的navigate()調(diào)用,如下例所示:

FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
    .addSharedElement(imageView, "header_image")
    .addSharedElement(titleView, "header_title")
    .build();
Navigation.findNavController(view).navigate(R.id.details,
    null, // Bundle of args
    null, // NavOptions
    extras);
活動(dòng)目標(biāo)共享元素轉(zhuǎn)換

活動(dòng)依賴于ActivityOptionsCompat來控制共享元素轉(zhuǎn)換,詳見使用共享元素文檔啟動(dòng)活動(dòng),如下例所示:

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
        Pair.create(imageView, "header_image"),
        Pair.create(titleView, "header_title"));

ActivityNavigator.Extras extras = new ActivityNavigator.Extras(options);
Navigation.findNavController(view).navigate(R.id.details,
    null, // Bundle of args
    null, // NavOptions
    extras);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 畢業(yè)五年,全職家庭媽媽將近五年,感謝自己,保持上進(jìn),保持自省。 感謝網(wǎng)易公開課,感謝互聯(lián)網(wǎng),感謝全球化,受益了在世...
    師爺是枚美男子閱讀 179評(píng)論 0 1
  • 有些時(shí)候閑下來,一個(gè)人想想事,總是想著想著就想落淚了。這才意識(shí)到,突然間我大起來了,突然間要面對(duì)的事很多很多了...
    洛簡(jiǎn)紫閱讀 1,263評(píng)論 0 1

友情鏈接更多精彩內(nèi)容