iT邦幫忙

2022 iThome 鐵人賽

DAY 19
0
Mobile Development

【Kotlin Notes And JetPack】Build an App系列 第 19

Day 19.【Architecture】Navigation 的介紹與應用

  • 分享至 

  • xImage
  •  

除了使用 FragmentManager 之外,還有什麼方式可以切換我們的 fragment 呢!今天就要來認識一下 Navigation,以下如有解釋不清或是描述錯誤的地方還請大家多多指教:

什麼?

透過介面的形式來操作 fragment transaction, backstack, deeplink, 傳遞資料等相關頁面操作,而 navigation 包含以下這三個部分:

  • navigation.xml:也就是我們要實作的 xml 檔案,所有操作都必須透過這個檔案執行
  • NavHost:用來盛裝我們最後要呈現的 Fragment 容器
  • NavController:負責管理 NavHost 的內容物,替換裡面的 Fragment

至於資料傳遞有兩種方式可以實作:

| Safe Args

一種 gradle 的外掛程式,在頁面導轉時提供安全方式傳遞我們的資料,在使用之前必須分別在兩個 gradle 檔加上 plugin,要注意的是 gradle.properties 的檔案要有 android.useAndroidX=true

// project gradle
buildscript {
    repositories {
        google()
    }
    dependencies {
        def nav_version = "2.5.2"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}
// module gradle
plugins {
  id 'androidx.navigation.safeargs.kotlin'
}

並透過 by navArgs() 來取得傳遞的參數:

val args: HomeFragmentArgs by navArgs()

| Bundle

如果不使用 Safe Args 也可以透過 Bundle 來傳遞資料,使用 argument 取得資料:

arguments?.getString("name")

而參數傳遞有提供以下幾種 type:

| Argument Type

資料傳遞可支援以下型態,如果參數是 nullable 的狀態可以加入 android:defaultValue="@null"
https://ithelp.ithome.com.tw/upload/images/20221002/201511459MsVuMTZzI.png

如何?

| Set up

在 gradle 中加入 navigation 的 library

def nav_version = "2.5.2"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

| Navigation graph

先在 resource 建立 navigation 的檔案
https://ithelp.ithome.com.tw/upload/images/20221002/20151145oGywWEXPRP.png

並將 Main 的 XML 改成如下:

...
<androidx.fragment.app.FragmentContainerView
			android:id="@+id/myNavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:name="androidx.navigation.fragment.NavHostFragment"
            app:defaultNavHost="true"
            app:navGraph="@navigation/navigation"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
...

在 navigation 中加入主頁的 fragment:

<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/navigation"
            app:startDestination="@id/homeFragment">

    <fragment android:id="@+id/homeFragment"
              android:name="com.snc.weathby.HomeFragment"
              android:label="HomeFragment"
              tools:layout="@layout/fragment_home"/>
</navigation>

https://ithelp.ithome.com.tw/upload/images/20221002/20151145OF9298dAcR.png

透過左上方的按鈕來加入新的頁面:
https://ithelp.ithome.com.tw/upload/images/20221002/20151145MjwvWouOUc.png

| Set Argument

設置要傳入 detail 的 argument:

<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/navigation"
            app:startDestination="@id/homeFragment">

    <fragment android:id="@+id/homeFragment"
              android:name="com.snc.weathby.HomeFragment"
              android:label="HomeFragment"
              tools:layout="@layout/fragment_home">
        <action
               android:id="@+id/action_homeFragment_to_detailFragment"
               app:destination="@id/detailFragment" />
    </fragment>

    <fragment
            android:id="@+id/detailFragment"
            android:name="com.snc.weathby.detail.DetailFragment"
            android:label="fragment_detail"
            tools:layout="@layout/fragment_detail" >
        <argument
            android:name="city"
            app:argType="com.snc.weathby.home.CityCard" />
    </fragment>
</navigation>

資料型態我選擇傳入 Parcelable 資料,所以需要更動我的 data class,並在 gradle 加入 apply plugin: 'kotlin-parcelize' :

sealed class HomeVo(val id: Int)

@Parcelize
data class CityCard(
    val cityId: Int,
    val cityName: String,
    val day: String,
    val temp: Int,
    val wind: Int,
    val wet: Int,
    val rain: Int,
    val isMarked: Boolean,
    val dayTem: List<CityDayTemp>
) : HomeVo(cityId), Parcelable

@Parcelize
data class CityDayTemp(
    val day: String,
    val icon: IconType,
    val maxTemp: Int,
    val minTemp: Int
): Parcelable
...

| NavController

開始設置導轉頁面,並傳遞預設的假資料:

...
// Safe Args
private val cardAdapter by lazy { HomeCityAdapter(
    HomeCityAdapter.OnClickListener { it: CityCard // system display
	      val action = HomeFragmentDirections.actionHomeFragmentToDetailFragment(it)
	      this.findNavController().navigate(action)
    }
)}

// Bundle
private val cardAdapter by lazy { HomeCityAdapter(
    HomeCityAdapter.OnClickListener { it: CityCard // system display
	    val bundle = bundleOf("city" to it)
        this.findNavController().navigate(R.id.action_homeFragment_to_detailFragment, bundle)
    }
)}

actionHomeFragmentToDetailFragment 為 action 的 id @+id/action_homeFragment_to_detailFragment 編譯過來的。

在 detail 頁取得資料:

// Safe Args
val args: DetailFragmentArgs by navArgs()

private fun setupView() = binding.apply {
    args.city.also {
        cityName.text = it.cityName
        weekName.text = it.day
        cityTem.text = it.temp
        cityWindy.text = it.wind
        cityRainy.text = it.rain
        cityWet.text = it.wet
        dayTempList.adapter = listAdapter
        listAdapter.submitList(it.dayTem)
    }
}

// Bundle
private fun setupView() = binding.apply {
    arguments?.getParcelable<CityCard>("city")?.also {
        cityName.text = it.cityName
        weekName.text = it.day
        cityTem.text = it.temp
        cityWindy.text = it.wind
        cityRainy.text = it.rain
        cityWet.text = it.wet
        dayTempList.adapter = listAdapter
        listAdapter.submitList(it.dayTem)
    }
}

Reference

Navigation
Navigaiton argument


上一篇
Day 18.【Architecture】ViewBinding 的介紹與應用
下一篇
Day 20.【Architecture】Navigation Shared Element Transition
系列文
【Kotlin Notes And JetPack】Build an App30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言