LoginSignup
1
1

More than 3 years have passed since last update.

Sunflowerリポジトリで学ぶJetPack〜Navigation編

Last updated at Posted at 2020-07-26

新型コロナの影響で自宅待機になってしまい、その間勉強するものとしてSunflowerリポジトリを
勧めてもらいました。

JetPackのライブラリのうち、今回はNavigation編です

尚、引用しているソースは明記しているところ以外は、全てSunflowerのリポジトリのものです。 

環境

  • Android Studioは3.3以上が必要
  • 確認時は3.6.2を使用

Navgation を利用するのに必要なこと

大きく分けて3つ必要です
1. 準備(依存関係の記載)
1. レイアウトファイルにナビゲーションを使うことを記載する
3. ナビゲーション グラフのファイルを作る

準備

依存関係の記載

  • 公式によると、build.gradleに以下の4つの依存関係を記載する必要があります。
    • Java language implementation
    • Kotlin
    • Dynamic Feature Module Support
    • Testing Navigation

公式のbuild.gradleのサンプル

build.gradle
    dependencies {
      def nav_version = "2.3.0-alpha01"

      // Java language implementation
      implementation "androidx.navigation:navigation-fragment:$nav_version"
      implementation "androidx.navigation:navigation-ui:$nav_version"

      // Kotlin
      implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
      implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

      // Dynamic Feature Module Support
      implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"

      // Testing Navigation
      androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
    }

引用元:Navigation コンポーネント スタートガイド | 環境をセットアップする

gradleファイル

それでは、Sunflowerのbuild.gradleを見てみましょう。
Navigationと関係ないところは省略

build.gradle(sunflower)

build.gradle
buildscript {
    // Define versions in a single place
    ext {
               :
        navigationVersion = '2.2.0'
               :
        }
    dependencies {
               :
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
    }
}

公式のチュートリアルにはないものが含まれています!
こちらは safe argsの機能を利用する際に記載の必要があるものです。
Navgation利用時に安全にパラメータを渡す機能です。
こちらはrootbuild.gradleに記載する必要があるとのこと。
https://developer.android.com/guide/navigation/navigation-pass-data#Safe-args

build.gradle(:app)

app/build.gradle
dependencies {
              :
    implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.navigationVersion"
    implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion"
              :

$rootProject.navigationVersionbuild.gradle(sunflower)で定義しているnavigationVersion = '2.2.0'ですね

ここからわかること

  • Sunflowerリポジトリでは、下記のものは利用していないので、依存関係の記載がない。
    • Java
    • Dynamic Feature Module Support
    • Navigationのテスト
  • kotlinは使っているので、依存関係の記載がある。

layout

次にレイアウトファイルを見てみましょう。
最初に表示される画面から詳細画面に遷移するところで使っているはずなので、
最初に表示する画面を見てみます。
起動時のActivityGardenActivityでそこでsetContentViewしているxmlファイルはactivity_garden.xmlです
レイアウトはこんな感じ

activity_garden.xml

activity_garden.xml
<fragment
    android:id="@+id/nav_host"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_garden"/>
</FrameLayout>

お、やっぱりここにNavgation関連の設定をしています。

必要なこと

  1. android:name には androidx.navigation.fragment.NavHostFragmentを設定する
    • このfragmentNavigationを使うよ!
  2. app:navGraph には 利用するNavigationのXMLファイルを記載します。ここでNavGraphと関連付けます。
    • ナビゲーショングラフはこのファイルを使うよ!

その他

  • app:defaultNavHost="true"を設定すると、戻るボタンで戻るようになります。
    • 1つの画面に複数のFragmentがあり、両方でNavgationを利用している時などに、戻るボタンを効かなくする、 とかの時にはfalseにする模様

ナビゲーショングラフ

レイアウトで指定されていたnav_gardenのファイルを見てみましょう

Navigation Editor

NavEditor.png

こんな感じで、画面が複数と、その間を結ぶ矢印が表示されています。

XMLファイル

nav_garden.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/view_pager_fragment">

    <fragment
        android:id="@+id/view_pager_fragment"
        android:name="com.google.samples.apps.sunflower.HomeViewPagerFragment"
        tools:layout="@layout/fragment_view_pager">

        <action
                android:id="@+id/action_view_pager_fragment_to_plant_detail_fragment"
                app:destination="@id/plant_detail_fragment"
                app:enterAnim="@anim/slide_in_right"
                app:exitAnim="@anim/slide_out_left"
                app:popEnterAnim="@anim/slide_in_left"
                app:popExitAnim="@anim/slide_out_right" />

    </fragment>

    <fragment
        android:id="@+id/plant_detail_fragment"
        android:name="com.google.samples.apps.sunflower.PlantDetailFragment"
        android:label="@string/plant_details_title"
        tools:layout="@layout/fragment_plant_detail">
        <argument
            android:name="plantId"
            app:argType="string" />
    </fragment>

</navigation>

ポイント

  1. 最初に表示する画面が<navigation>タグのapp:startDestinationに記載されている。
  2. 画面遷移に関連する画面が<fragment>タグで記載されている。
  3. 画面遷移の処理詳細が、遷移元の画面に<action>タグで記載されている。
  4. 遷移先画面に渡されるパラメータが遷移先画面に<argment>タグで記載されている。

※この辺りは、Navigation Editorで画面をクリックしてグイーンとやって・・・みたいな感じで設定できる部分もあるようです!
iOSでいうStoryboardみたいな感じでしょうか?)
https://developer.android.com/guide/navigation/navigation-getting-started?hl=ja#Designate-start

actionタグ設定値の記載方法について

特有の設定値については下記となっています。
※アニメーション関連の設定値が分かりづらかったので
こちらを参照しました
https://stackoverflow.com/questions/56285197/what-is-the-difference-between-enteranim-popenteranim-exitanim-popexitanim
https://developer.android.com/guide/navigation/navigation-animate-transitions

つまるところ、アニメーションはPUSH時とPOP時で分けて記述が可能ということのようです。

名称 内容    設定されている値      
android:id     遷移アクションの名称(これをソース内に記載する) @id/action_view_pager_fragment_to_plant_detail_fragment
app:destination 遷移先の画面(宛先) @id/plant_detail_fragment
app:enterAnim 宛先に遷移する際のアニメーション @anim/slide_in_right
app:exitAnim 宛先からに出て行く時のアニメーション @anim/slide_out_left
app:popEnterAnim 宛先にPOPで遷移する時のアニメーション @anim/slide_in_left
app:popExitAnim 宛先からPOPで出て行く時のアニメーション @anim/slide_out_right

使用箇所について

  • RecyclerViewの項目をタップした時に、navigatioToPlantで画面遷移を実施している。
  • navigatioToPlantactionViewPagerFragmentToPlantDetailFragment(plantId)で遷移先を決定するNavDirectionsを取得している。
  • NavDirectionsの取得にはNavDirectionsインターフェースを継承したクラスActionViewPagerFragmentToPlantDetailFragmentのコンストラクタActionViewPagerFragmentToPlantDetailFragment(plantId)使用している。
  • ActionViewPagerFragmentToPlantDetailFragmentクラスでは、NavDirectionsインターフェースのgetActionId()メソッドをオーバーライドしている。
  • getActionId()メソッドは action_view_pager_fragment_to_plant_detail_fragmentから取得している。
    ⬆︎先ほどナビゲーショングラフのXMLファイルで定義していたactionのIDですね!(やっと出てきた!(^^;;)
GardenPlantingAdapter.kt
    class ViewHolder(
        private val binding: ListItemGardenPlantingBinding
    ) : RecyclerView.ViewHolder(binding.root) {
        init {
            binding.setClickListener { view ->
                binding.viewModel?.plantId?.let { plantId ->
                    navigateToPlant(plantId, view)
                }
            }
        }

        private fun navigateToPlant(plantId: String, view: View) {
            val direction = HomeViewPagerFragmentDirections
                .actionViewPagerFragmentToPlantDetailFragment(plantId)
            view.findNavController().navigate(direction)
        }
HomeViewPagerFragmentDirections.kt
class HomeViewPagerFragmentDirections private constructor() {
  private data class ActionViewPagerFragmentToPlantDetailFragment(
    val plantId: String
  ) : NavDirections {
    override fun getActionId(): Int = R.id.action_view_pager_fragment_to_plant_detail_fragment

    override fun getArguments(): Bundle {
      val result = Bundle()
      result.putString("plantId", this.plantId)
      return result
    }
  }

  companion object {
    fun actionViewPagerFragmentToPlantDetailFragment(plantId: String): NavDirections =
        ActionViewPagerFragmentToPlantDetailFragment(plantId)
  }
}

引数の設定

遷移先の画面のタグ内の<argument>タグ内に、
遷移先画面で受け取る引数を設定可能

名称 内容    設定されている値      
android:name 引数の名前 plantId
app:argType 引数の型 string

遷移先での引数の取得

遷移先のコードは下記です。

PlantDetailFragment.kt
private val args: PlantDetailFragmentArgs by navArgs()

private val plantDetailViewModel: PlantDetailViewModel by viewModels {
    InjectorUtils.providePlantDetailViewModelFactory(requireActivity(), args.plantId)
}

公式のドキュメント
https://developer.android.com/guide/navigation/navigation-pass-data?hl=ja#Safe-args
によると、

受信側デスティネーションのコード内で、getArguments() メソッドを使用して、バンドルを取得し、そのコンテンツを使用します。-ktx 依存関係を使用している場合、Kotlin ユーザーは、by navArgs() プロパティ デリゲートを使用して引数にアクセスすることもできます。

なるほど-
ここではsafe argsという機能を利用して、遷移元から渡されたデータを遷移先でargsという変数で取得し、
それをViewModelに入れてますねー。
で、画面ではそのViewModelを介してデータを使用するようになっています。

まとめ

Sunflowerのリポジトリでは

  • KotlinNavigationを利用している
  • Navigationを利用する時ために、以下のところを追加・変更している
    • レイアウト
    • ナビゲーショングラフ
    • 呼び出し元
    • 呼び出し先で引数の取得
  • Safe Argsという機能で遷移元から遷移先へデータを渡している

以上です!

参考サイト

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1