1.Introduce
導(dǎo)航組件簡化了導(dǎo)航的實(shí)現(xiàn),也可以實(shí)現(xiàn)導(dǎo)航流程的可視化。navigation庫提供了一系列便捷:
- 自動處理fragment transactions
- Correctly handling up and back by default
- Default behaviors for animations and transitions
- Deep linking as a first class operation
- 只需要一點(diǎn)點(diǎn)額外工作就可以實(shí)現(xiàn)導(dǎo)航UI模板(就像navigation drawers 和 bottom nav)
- Type safety when passing information while navigating
- Android studio提供了app導(dǎo)航的可視化和導(dǎo)航流的編輯
BEHOLD:

2.Getting Start
$ git clone https://github.com/googlecodelabs/android-navigation
Navigation概述
導(dǎo)航組件包括三個關(guān)鍵部分:
- Navigation Graph(新的xml資源) :This is a resource that contains all navigation-related information in one centralized location. This includes all the places in your app, known as destinations, and possible paths a user could take through your app
- NavHostFragment(XML布局視圖):This is a special widget you add to your layout. It displays different destinations from your Navigation Graph.
- NavController(一個Object):This is an object that keeps track of the current position within the navigation graph. It orchestrates swapping destination content in the NavHostFragment as you move through a navigation graph.
3.Introduce the Navigation Graph
Destinations(目的地)
導(dǎo)航組件引入了Destination的概念。Destination是應(yīng)用中可以導(dǎo)航到達(dá)的任意位置,一般來講是一個fragment或者activity。These are supported out of the box, but you can also make your own custom destination types if needed。
Navigation Graph(導(dǎo)航圖)
導(dǎo)航圖是一種新的資源類型,定義了應(yīng)用中用戶可以使用的所有路徑。它直觀地顯示了一個目的地(Destination)可以到達(dá)的所有其他的目的地。下面是練習(xí)中導(dǎo)航的起始狀態(tài):

Navigation Editor(導(dǎo)航編輯器)
- 打開 res/navigation/mobile_navigation.xml
- 點(diǎn)Design
image.png
image.png
destination之間的箭頭叫做action,這個我們晚一點(diǎn)討論。 -
點(diǎn)擊一個destination查看屬性
image.png
4.查看action的屬性,點(diǎn)擊箭頭就可以了
分析navigation的XML文件
<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"
app:startDestination="@+id/home_dest">
<!-- ...tags for fragments and activities here -->
</navigation>
<navigation>是導(dǎo)航圖的根節(jié)點(diǎn)
<navigation>包含一個或多個destination,<activity>或<fragment>
-
app:startDestination定義app打開時默認(rèn)加載的destination
下面是一個fragment destination<fragment android:id="@+id/flow_step_one_dest" android:name="com.example.android.codelabs.navigation.FlowStepFragment" tools:layout="@layout/flow_step_one_fragment"> <argument .../> <action android:id="@+id/next_action" app:destination="@+id/flow_step_two_dest"> </action> </fragment> android:id 就是一個id
android:name 引用的fragment的全路徑
tools:layout 導(dǎo)航圖中顯示的布局哦
4.給Navigation Graph添加一個Destination
- 打開mobile_navigation.xml,進(jìn)入design模式
- 點(diǎn)擊new Destination,選擇settings_fragment
5.使用導(dǎo)航圖進(jìn)行導(dǎo)航
Activity和Navigation
導(dǎo)航組件遵循著Principles of Navigation中敘述的指導(dǎo)思想。指導(dǎo)中提到應(yīng)該用activity作為app的入口,而且activity中應(yīng)該包含全局導(dǎo)航,比如bottom nav,
比較下來, fragments will be the actual destination-specific layouts.
To get this all to work,需要讓activity包含一個叫做NavHostFragment的特殊部件。一個NavHostFragment會根據(jù)導(dǎo)航圖中的導(dǎo)航交換不同的fragment destination。

舉個栗子:
<LinearLayout
.../>
<androidx.appcompat.widget.Toolbar
.../>
<fragment
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/mobile_navigation"
app:defaultNavHost="true"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
.../>
</LinearLayout>
- 以上是一個activity的layout,包含了全局導(dǎo)航:一個bottom nav和一個toolbar
- android:name="androidx.navigation.fragment.NavHostFragment"和app:defaultNavHost="true"把系統(tǒng)后退按鈕連接到NavHostFragment
- app:navGraph="@navigation/mobile_navigation"將HavHostFragment和導(dǎo)航圖關(guān)聯(lián)起來,導(dǎo)航圖中定義了在NavHostFragment中可以導(dǎo)航的所有destinatioin
NavController
當(dāng)用戶進(jìn)行一些操作,比如點(diǎn)擊了某個按鈕,就需要觸發(fā)導(dǎo)航命令,NavController就是觸發(fā)NavHostFragment交互fragment的指定類。
// Command to navigate to flow_step_one_dest
findNavController().navigate(R.id.flow_step_one_dest)
這里傳入destination的id或者action的id都可以哦。
NavController很強(qiáng)大的,當(dāng)調(diào)用navigate()或者popBackStack()時,它會把這些命令根據(jù)destination的來(from)或去(to)轉(zhuǎn)換成適當(dāng)?shù)目蚣懿僮?。比如,?dāng)對一個activity destination調(diào)用navigation()時,NavController會調(diào)用startActivity()。
獲取與NavHostFragment相關(guān)的NavController有幾個途徑。在Kotlin中,根據(jù)在fragment,activity或者view中獲取NavController,推薦從以下選擇:
Fragment.findNavController()View.findNavController()-
Activity.findNavController(viewId: Int)
注意:NavController是和NavHostFragment相關(guān)的,所以不論使用哪個方法,都必須保證fragment,view,或者view id是NavHostFragent本身,或者有NavHostFragment作為Parent,否則會誕生IllegalStateException。
使用NavContriller導(dǎo)航去一個Destination
是時候表演真正的技術(shù)了,現(xiàn)在將要點(diǎn)擊“Navigate To Destination”按鈕導(dǎo)航去flow_step_one_dest destination(FlowStepFragment):
- 打開HomeFragment.kt
- 在onViewCreated()中搞navigate_destination_button
val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener {
findNavController().navigate(R.id.flow_step_one_dest)
}
或者
val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener( Navigation.createNavigateOnClickListener(R.id.flow_step_one_dest, null)
)
都可以


