導(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)類型。

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

導(dǎo)航編輯器的部分是:
- “目標(biāo)”列表 - 列出“曲線圖編輯器”中當(dāng)前的所有目標(biāo)。
- 圖表編輯器 - 包含導(dǎo)航圖的可視化表示。
- 屬性編輯器 - 包含與導(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)使用以下步驟。
在“曲線圖編輯器”中,單擊“New Destination” 出現(xiàn)“New Destination”對(duì)話框。
單擊“Create blank destination”或單擊片段或活動(dòng)。 將出現(xiàn)“新建Android組件”對(duì)話框。
在“片段名稱”字段中輸入名稱。 此名稱是片段類的名稱。
在“片段布局名稱”字段中輸入名稱。 此名稱是片段的布局文件的名稱。
單擊完成。 表示目標(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)有目的地。

- 單擊新插入的目標(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)類的名稱。
- 單擊“文本”選項(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è)目的地:
-
在圖表編輯器中,將鼠標(biāo)懸停在您希望用戶導(dǎo)航的目標(biāo)的右側(cè)。 目的地上會(huì)出現(xiàn)一個(gè)圓圈。
圖4.動(dòng)作連接圈 -
單擊并按住,將光標(biāo)拖動(dòng)到希望用戶導(dǎo)航到的目標(biāo)上,然后釋放。 繪制一條線以指示兩個(gè)目的地之間的導(dǎo)航。
圖5.連接的目的地 單擊箭頭以突出顯示該操作。 “屬性”面板中顯示以下屬性:
- “類型”字段包含“操作”。
- ID字段包含系統(tǒng)為操作分配的ID。
- Destination字段包含目標(biāo)片段或活動(dòng)的ID。
- 單擊“文本”選項(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):
- 從圖表編輯器中,單擊目標(biāo)。 目的地突出顯示。
- 單擊“屬性”面板中的“設(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ù)中的說明。
- 在圖表編輯器中,單擊接收參數(shù)的目標(biāo)位置。 目的地亮點(diǎn)。
- 單擊“屬性”面板的“參數(shù)”部分中的“添加”(+)。 出現(xiàn)空名稱和默認(rèn)值字段。
- 雙擊名稱并輸入?yún)?shù)的名稱。
- 按Tab鍵并輸入?yún)?shù)的默認(rèn)值。
- 單擊此目標(biāo)之前的操作。 參數(shù)默認(rèn)值應(yīng)包含新添加的參數(shù)。
- 單擊“文本”選項(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” />
- 在您的代碼中,使用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。
- 在圖表編輯器中,單擊接收參數(shù)的目標(biāo)位置。 目的地亮點(diǎn)。
- 單擊“屬性”面板的“參數(shù)”部分中的+。 出現(xiàn)空名稱和默認(rèn)值字段。
- 雙擊名稱并輸入?yún)?shù)的名稱。
- 按Tab鍵并從下拉列表中選擇參數(shù)的類型。
- 按Tab鍵并輸入?yún)?shù)的默認(rèn)值。
- 單擊此目標(biāo)之前的操作。 參數(shù)默認(rèn)值應(yīng)包含新添加的參數(shù)。
- 單擊“文本”選項(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è)流程:允許用戶匯款的流程和允許用戶查看其余額的流程。

要將目標(biāo)分組到嵌套圖中:
在“曲線圖編輯器”中,按住shift并單擊要包含在嵌套圖形中的目標(biāo)。 每個(gè)目的地都突出顯示
-
打開上下文菜單,然后選擇“移動(dòng)到嵌套圖形”>“新建圖形”。 目標(biāo)包含在嵌套圖中。 圖7顯示了Graph Editor中的嵌套圖。
圖4. Graph Editor中的嵌套圖 單擊嵌套圖以突出顯示它。 “屬性”面板中顯示以下屬性:
- “類型”字段包含“嵌套圖”。
- ID字段包含嵌套圖的系統(tǒng)分配ID。 此ID用于引用代碼中的嵌套圖。
- 雙擊嵌套圖。 將顯示嵌套圖中的目標(biāo)。
- 在“目標(biāo)”列表中,單擊“根”以返回到根導(dǎo)航圖。
- 單擊“文本”選項(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>
- 在您的代碼中,將連接根圖的操作的資源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í)行以下操作:
- 從圖表編輯器中,選擇深層鏈接的目標(biāo)。
- 單擊“屬性”面板的“深層鏈接”部分中的+。 將出現(xiàn)“添加深層鏈接”對(duì)話框。
- 在URI字段中鍵入U(xiǎn)RI,例如“
www.cashdog.com/sendmoney”,它表示應(yīng)用程序中發(fā)送貨幣嵌套圖的起始目的地。
請(qǐng)注意以下事項(xiàng):
- 沒有方案的URI被假定為http和https。 例如,
www.cashdog.com與http://www.cashdog.com和https://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è)字符。
- (可選)選中“自動(dòng)驗(yàn)證”以要求Google驗(yàn)證您是URI的所有者。 有關(guān)更多信息,請(qǐng)參閱驗(yàn)證Android應(yīng)用程序鏈接。
- 單擊添加。 所選目標(biāo)上方會(huì)顯示一個(gè)鏈接圖標(biāo),表示該目標(biāo)具有深層鏈接。
- 單擊“文本”選項(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)換:
- 創(chuàng)建動(dòng)畫資源文件。導(dǎo)航架構(gòu)組件支持屬性和視圖動(dòng)畫。有關(guān)更多信息,請(qǐng)參閱動(dòng)畫資源。
- 在“曲線圖編輯器”中,單擊應(yīng)進(jìn)行過渡的操作。
- 在“屬性”面板的“過渡”部分中,單擊“輸入”旁邊的向下箭頭。將顯示項(xiàng)目中的轉(zhuǎn)換列表。
- 選擇用戶進(jìn)入目的地時(shí)發(fā)生的轉(zhuǎn)換。
- 在“屬性”面板的“過渡”部分中,單擊“退出”旁邊的向下箭頭。將顯示項(xiàng)目中的轉(zhuǎn)換列表。
- 選擇用戶退出目標(biāo)時(shí)發(fā)生的轉(zhuǎn)換。
- 單擊“文本”選項(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);


