這次會在 App 裡使用 Navigation Component ,我自己對他的認知是把 UI 跳轉簡化,並且讓我們更輕易的做到 1 Activity + 許多 Fragment 這樣的 UI 設計方式。
不多說我們現在就開始吧!
// project build.gradle
buildscript {
dependencies {
......
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0"
}
}
// app build.gradle
apply plugin: "androidx.navigation.safeargs.kotlin"
......
dependencies {
def nav_version = "2.1.0"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
另外要注意的是 AS 的版本至少要在 3.3 以上。
首先在 res/navigation 資料夾創建一個 Navigation Graph:
Navigation graph 是一個包含所有目的地(destinations)及行動(actions)的資源,並且可以以類似 Story Board 的形式進行編輯。
這邊我想要做一個有側邊欄的 Activity ,所以我會事先建立好需要的 menu 及 xml。
那麼首先打開 Activity 的 xml 修改一下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.TasksActivity"
tools:openDrawer="start">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="@style/Toolbar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:id="@+id/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/nav_graph"/>
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header"
app:itemIconTint="@drawable/drawer_item_color"
app:itemTextColor="@drawable/drawer_item_color"
app:menu="@menu/drawer_actions"/>
</androidx.drawerlayout.widget.DrawerLayout>
關於如何創建側邊欄就不細說了,可以看到我在 Activity 內創建了 <fragment>
標籤,android:name
指定了 NavHostFragment
。
所有 navigation 都必須實現 NavHost
,而 Google 已經幫我們默認實現了一個 NavHostFragment
,NavHostFragment 提供了一個 UI 區域,讓我們可以透過它來把 Activity 上的 UI 切換到不同的 Fragment View。
app:navGraph
指定了剛剛建立的 nav_graph
,讓 NavHostFragment
能夠知道他可以導航到的目標。
至於 app:defaultNavHost="true"
則可以讓 NavHostFragment
攔截系統的 back 按鈕,並且表示這是 App 的 Home Page。
理論上如果 app 需要有多個 Activity ,那麼每個 Activity 上的 NavHostFragment
就會有對應的 Navigation graph ,個人認為這也可以幫助我們開發時對於不同功能的需求及設計可以清楚的劃分開來。
我們先建立一個 TasksFragment,這會是我們的 App 啟動後的第一個 UI 介面,接著到 nav_graph 上新增第一個 Destination ,Navigation Component 會把第一個建立的 Destination 當作是 Navigation 的起始頁,具體流程如下:
接下來單擊新增的 Fragment,右邊會有一個 Attribute 選單,可以看到幾個屬性:
由於現在才建立第一個 Destination ,所以預設 destination 就是當前的 Fragment 。
如果想要變更開始時的 destination ,可以點擊要當作預設 destination 的 Fragment,選擇上方一個房屋的按鈕 "Assign start destination" ,用來指定 Navigation graph 的開始 destination ,如果成功的話 graph 上的 Fragment 會有一個房屋的圖案。
再來新增一個 StatisticFragment ,依照上個步驟加入到 graph 中,接著從 Home Fragment 拉出一條線到 StatisticFragment 上,一個簡單的 action
就完成了。點擊箭頭可以看到 Action 的各個屬性。
其中,Type
用來表示在這個 graph 裡的類型,這裡表明是一個 action; ID
用來命名這個 Action,而 Destination
則是用來設定要跳轉的目標 Fragment 。
設定好 Action 就可以準備實現類似 Activity/Fragment 的 intent
功能了。
每個 NavHost
裡都有一個 Controller 叫做 NavController
,用來控制跳轉到目標 Destination ,擁有了 NavController
後就可以調用 navigate()
實現跳轉:
// TasksFragment
private fun navigateToStatistic() {
// Fragment.findNavController()
findNavController().navigate()
}
如果在 Destination 有實現 Argument 時,就會需要在 Action 裡傳入必要的參數:
private fun navigateToStatistic() {
// 這裡我的 Argument 是一個 nullable 的 String
val action = TasksFragmentDirections
.actionTasksFragmentToStatisticFragment(null)
findNavController().navigate(action)
}
Navigation Component 的基本介紹大概結束了,明天會繼續完成專案內的 Navigation Component 。