思考幾個(gè)問題:
- 可以在代碼中用Bundle傳遞參數(shù),為什么要在XML去配置
- XML中的參數(shù)標(biāo)簽,只能設(shè)置和讀取,無法在XML中跳轉(zhuǎn)是附帶傳過去,如B頁面要求傳入name:String,于是在<Argment>標(biāo)簽中配置,但A去跳轉(zhuǎn)時(shí),無法在XML中傳入,只能在代碼中定義參數(shù)名稱和值,那么XML的參數(shù)還有何意義?有什么實(shí)用的場景?
- navigationUp和popBackStack()回退上一級(jí)時(shí)有什么區(qū)別,該如何正確使用
- 跳轉(zhuǎn)時(shí) 有時(shí)用的是Action的ID,有時(shí)用的是Fragment的ID 他倆到底在什么場景下,區(qū)分該將哪個(gè)傳入方法作為參數(shù)
使用和核心方法
1.創(chuàng)建NavGraph

<?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/nav_graph"
app:startDestination="@id/home_fragment">
<fragment
android:id="@+id/home_fragment"
android:name="org.devio.proj.navigationdemo.HomeFragment"
android:label="@string/hello_blank_fragment"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/home_to_other"
app:destination="@id/other_fragment"
app:enterAnim="@anim/fade_in"
app:exitAnim="@anim/fade_out" />
</fragment>
<fragment
android:id="@+id/other_fragment"
android:name="org.devio.proj.navigationdemo.OtherFragment"
android:label="@string/hello_blank_fragment"
tools:layout="@layout/fragment_other">
<action
android:id="@+id/other_to_deeplink"
app:destination="@id/nav_graph_to" />
<argument
android:name="home_arg_name"
android:defaultValue="defName"
app:argType="string"
app:nullable="true" />
<argument
android:name="home_arg_age"
android:defaultValue="99"
app:argType="integer" />
<argument
android:name="home_arg_mode"
app:argType="org.devio.proj.navigationdemo.Model" />
<!-- <deepLink-->
<!-- android:id="@+id/deepLink"-->
<!-- app:uri="www.baidu.com" />-->
<!-- android:autoVerify="false"
app:action="ACTION_SEND"
app:mimeType="text/html"-->
</fragment>
<navigation
android:id="@+id/nav_graph_to"
android:label="SecondHome"
app:startDestination="@id/deep_link_fragment">
<fragment
android:id="@+id/deep_link_fragment"
android:name="org.devio.proj.navigationdemo.DeeplinkFragment"
android:label="@string/hello_blank_fragment"
tools:layout="@layout/fragment_deeplink">
<action
android:id="@+id/deeplink_to_home"
app:popUpTo="@id/home_fragment" />
</fragment>
<fragment
android:id="@+id/settingFragment"
android:name="org.devio.proj.navigationdemo.SettingFragment"
android:label="fragment_setting"
tools:layout="@layout/fragment_setting" />
</navigation>
</navigation>
==navigation== :視圖導(dǎo)航的根部標(biāo)簽, ==app:startDestination="@id/home_fragment"== 指定以哪個(gè)頁面為首頁。<navigation> 標(biāo)簽下包含3中子標(biāo)簽。:
<activity></activity> 支持Activity 跳轉(zhuǎn)
<dialog></dialog> 支持 dialogFragment 跳轉(zhuǎn)
<fragment></fragment> 支持fragment 跳轉(zhuǎn)
出以上三種跳轉(zhuǎn)類型外,==</navigation>== 標(biāo)簽下還支持嵌套操作。
<navigation>
<navigation>
</navigation>
<include >// 嵌套另一個(gè)nav_graph ,注意:
這個(gè)布局只能是<navigation>為根節(jié)點(diǎn)的布局
</include>
</navigation>
以Fragment為例,創(chuàng)建3個(gè)Fragment實(shí)例,分別為HomeFragment,OtherFragment,DeeplinkFragment。
<?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/nav_graph"
app:startDestination="@id/home_fragment">
<fragment
android:id="@+id/home_fragment"
android:name="org.devio.proj.navigationdemo.HomeFragment"
android:label="@string/hello_blank_fragment"
tools:layout="@layout/fragment_home">
</fragment>
<fragment
android:id="@+id/other_fragment"
android:name="org.devio.proj.navigationdemo.OtherFragment"
android:label="@string/hello_blank_fragment"
tools:layout="@layout/fragment_other">
</fragment>
<navigation
android:id="@+id/nav_graph_to"
android:label="SecondHome"
app:startDestination="@id/deep_link_fragment">
<fragment
android:id="@+id/deep_link_fragment"
android:name="org.devio.proj.navigationdemo.DeeplinkFragment"
android:label="@string/hello_blank_fragment"
tools:layout="@layout/fragment_deeplink">
<action
android:id="@+id/deeplink_to_home"
app:popUpTo="@id/home_fragment" />
</fragment>
<fragment
android:id="@+id/settingFragment"
android:name="org.devio.proj.navigationdemo.SettingFragment"
android:label="fragment_setting"
tools:layout="@layout/fragment_setting" />
</navigation>
</navigation>
id 當(dāng)前節(jié)點(diǎn)的唯一標(biāo)識(shí)
name <fragment/> 節(jié)點(diǎn)對(duì)應(yīng)的Fragment全類名
label 節(jié)點(diǎn)說明,當(dāng)與BottomNavigationView組合使用時(shí),字符串內(nèi)容會(huì)成為頁面的title
tools:layout coding時(shí),查看界面內(nèi)容
2.節(jié)點(diǎn)下參數(shù)配置說明
==注:== 節(jié)點(diǎn)的含義,即表示 <Activity> <Fragment>,<DialogFragment>

點(diǎn)擊右上角Design,進(jìn)入Navigation,視圖導(dǎo)航編輯頁面。左側(cè)為添加一個(gè)


==右側(cè)是為節(jié)點(diǎn)添加支持的屬性:==

2.1 跳轉(zhuǎn)當(dāng)前頁面所需參數(shù) (Argments)
跳轉(zhuǎn),回退當(dāng)前節(jié)點(diǎn)所需要的參數(shù)。
Name: 參數(shù)名稱,等同于intent.getString(key,value)中的Key
Type: 參數(shù)類型
Array: 是否是數(shù)組(String[])
Nullable: 是否可以為空
Default Value 為空的時(shí)的默認(rèn)值
更多支持的參數(shù)類型:

2.2 跳轉(zhuǎn)路由動(dòng)作 (Action)

ID 當(dāng)前跳轉(zhuǎn)動(dòng)作節(jié)點(diǎn)的唯一標(biāo)識(shí),后續(xù)在代碼中調(diào)用navController.navigation(R.id.ID)會(huì)用到,即執(zhí)行當(dāng)前配置的Action,同時(shí)也可使用想要跳轉(zhuǎn)目標(biāo)頁的ID
From 所配置的當(dāng)前節(jié)點(diǎn),點(diǎn)擊給那個(gè)節(jié)點(diǎn)配置,默認(rèn)就是哪個(gè)。選中后不可更改
Destination 跳轉(zhuǎn)的目標(biāo)節(jié)點(diǎn),即那個(gè)Fragment
enter:進(jìn)入動(dòng)畫
Exit :退出動(dòng)畫
Pop Enter : 上一節(jié)點(diǎn)出棧當(dāng)前節(jié)點(diǎn)的動(dòng)畫
Pop Exit: 上一節(jié)點(diǎn)回退棧到當(dāng)前節(jié)點(diǎn)的動(dòng)畫
Pop To 按返回鍵會(huì)調(diào)用 navController.navigationUp或navController.popBackStack()時(shí),想回退定向到那個(gè)節(jié)點(diǎn)
Inclusive: 很重要 多次出現(xiàn)。加入A->B->C,C的Pop To為B,當(dāng)Inclusive 為true,則表示B也退出,直接進(jìn)入到A,false回退到B
Single Top 類似Activity的SingleInscance,管理?xiàng)V杏邢嗤墓?jié)點(diǎn),則不會(huì)創(chuàng)建,同時(shí)棧內(nèi)此節(jié)點(diǎn)的上面的節(jié)點(diǎn),全部出棧。
2.3 Deeplink
<deepLink
android:id="@+id/deepLink"
android:autoVerify="false"
app:action="ACTION_SEND"
app:mimeType="text/html"
app:uri="www.baidu.com" />
理解nav_graph.xml后,在MainActivity中配置如下配置文件:
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
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/nav_graph" />
以上3個(gè)配置比較重要:
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"
android:name="androidx.navigation.fragment.NavHostFragment"
三個(gè)必配項(xiàng)。
- 攔截返回鍵的點(diǎn)擊事件,這樣Fragment就可以想Activity一樣,具有回退,返回事件
- 配置路由XML文件,然后加載進(jìn)NavHostFragment中 app:navGraph屬性,對(duì)應(yīng)的就是NavGraph這個(gè)類
- NavHostFragment是Navigation提供的默認(rèn)容器,所有路由邏輯都經(jīng)過這里,然后在分發(fā)出去
3. 代碼實(shí)現(xiàn)路由跳轉(zhuǎn)和方法解析
3.1 核心方法
Acitivty#findNavController() 傳入navGraph id
Fragment#findNavController() 直接調(diào)用
Navigation.findNavController() 傳入View
==navController.navigate()==
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val homeText = view.findViewById<TextView>(R.id.home_text)
homeText.setOnClickListener {
val model = Model("Jack", 16)
val bundle = Bundle()
bundle.putString("home_arg_name", "Tom")
bundle.putInt("home_arg_age", 12)
bundle.putParcelable("home_arg_mode", model)
// arguments?.let {
// it.putString("home_arg_name", "Tom")
// it.putInt("home_arg_age", 12)
// it.putParcelable("home_arg_mode", model)
// }
// val navOptions = navOptions {
// arguments?.let {
// it.putString("home_arg_name", "Tom")
// it.putInt("home_arg_age", 12)
// it.putParcelable("home_arg_mode", model)
// }
// }
findNavController().navigate(R.id.home_to_other, bundle)
// findNavController().navigate(R.id.home_to_other)
// findNavController().navigateUp()
// findNavController().popBackStack()
}
}
navigate() 傳入節(jié)點(diǎn)ID 表示路由到節(jié)點(diǎn)所在頁面,
傳入Action ID 表示執(zhí)行XML <Action>中的路由規(guī)則,同時(shí)還支持Deeplink跳轉(zhuǎn)
navigateUp()和popBackStack()都表示回退上頁面,但navigateUp()在Deeplink的情況下 應(yīng)用1a(deeplink)路由到應(yīng)用2的B后navigateUp()返回到a,而popBackStack()則會(huì)返回到當(dāng)前棧內(nèi)的上一層(A)
另一個(gè)區(qū)別是popBackStack()支持回退到指定頁面,inclusive參數(shù),之前有提到過
bundle 設(shè)置傳遞參數(shù) Options設(shè)置其他配置參數(shù),如動(dòng)畫,popUpTo等,也就說,在XML中的配置,在代碼中都可實(shí)現(xiàn)。
那么參數(shù)中的配置argument在什么場景下比較合適。答案是:一些固定配置參數(shù)。例如loginFragment。A,B頁面都會(huì)進(jìn)入Login頁面,但它們有不同的權(quán)限,所以可以配置不同的type,且這種配置基本不會(huì)變化。
4. 源碼分析
4.1 源碼中出現(xiàn)的個(gè)各類和職責(zé)

下篇將從這張圖入手,開始源碼分析,并利用實(shí)戰(zhàn)改造