iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 8
0
自我挑戰組

Android Architecture 及 Unit Test系列 第 8

[Day 8] Navigation Component:Part 1

  • 分享至 

  • xImage
  •  

這次會在 App 裡使用 Navigation Component ,我自己對他的認知是把 UI 跳轉簡化,並且讓我們更輕易的做到 1 Activity + 許多 Fragment 這樣的 UI 設計方式。

不多說我們現在就開始吧!

Gradle

// 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 以上。

創建 Navigation Graph

首先在 res/navigation 資料夾創建一個 Navigation Graph:

Navigation graph 是一個包含所有目的地(destinations)及行動(actions)的資源,並且可以以類似 Story Board 的形式進行編輯。

  • Destination:表示 app 中要跳轉 UI 目的地,在這裡指的就是各個 Fragment 。
  • Action:各個 Destination 之間的連結,表示 UI 可以跳轉的路徑。

將 Navigation Graph 加入到 Activity

這邊我想要做一個有側邊欄的 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 ,個人認為這也可以幫助我們開發時對於不同功能的需求及設計可以清楚的劃分開來。

將目的地加入到 Navigation graph

我們先建立一個 TasksFragment,這會是我們的 App 啟動後的第一個 UI 介面,接著到 nav_graph 上新增第一個 Destination ,Navigation Component 會把第一個建立的 Destination 當作是 Navigation 的起始頁,具體流程如下:

接下來單擊新增的 Fragment,右邊會有一個 Attribute 選單,可以看到幾個屬性:

  • Type:表示選擇的元件類型,這時顯示的是 Fragment
  • Label:其實就是 Fragment 的 Title Name
  • ID:指的是在 Navigation 裡的名稱
  • Class:跟這個 Destination 相關連的 class ,一般就是這個 View 的 Fragment
  • Argument:跳轉到這個 Destination 時需要傳入的參數

由於現在才建立第一個 Destination ,所以預設 destination 就是當前的 Fragment 。

如果想要變更開始時的 destination ,可以點擊要當作預設 destination 的 Fragment,選擇上方一個房屋的按鈕 "Assign start destination" ,用來指定 Navigation graph 的開始 destination ,如果成功的話 graph 上的 Fragment 會有一個房屋的圖案。

連接 Destination

再來新增一個 StatisticFragment ,依照上個步驟加入到 graph 中,接著從 Home Fragment 拉出一條線到 StatisticFragment 上,一個簡單的 action 就完成了。點擊箭頭可以看到 Action 的各個屬性。

其中,Type 用來表示在這個 graph 裡的類型,這裡表明是一個 action; ID 用來命名這個 Action,而 Destination 則是用來設定要跳轉的目標 Fragment 。

設定好 Action 就可以準備實現類似 Activity/Fragment 的 intent 功能了。

跳轉到目標 Destination

每個 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 。


上一篇
[Day 7] Android Architecture Components:LiveData
下一篇
[Day 9] Navigation Component:Part 2
系列文
Android Architecture 及 Unit Test30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言