Android
navigation
android開発
Jetpack

初めてのNavigationArchitectureComponent

今回はNavigationを使ってみます。

導入

app/build.gradleのdependenciesに以下を追加します。

    implementation "android.arch.navigation:navigation-fragment:1.0.0-alpha02"
    implementation "android.arch.navigation:navigation-ui:1.0.0-alpha02"
    implementation "android.arch.navigation:navigation-fragment-ktx:1.0.0-alpha02"
    implementation "android.arch.navigation:navigation-ui-ktx:1.0.0-alpha02"

リソースファイルの準備

中身がなくていいので、Fragmentを用意しておきます。
res/navigation配下に好きな名前のnavigation定義ファイルを用意します。
※navigationディレクトリが無ければ追加してください
※navigationのxmlを開いてもxml編集しか出来ない場合はASの設定を直す必要があります。
スクリーンショット 2018-12-19 17.32.26.png

直感操作で大丈夫だと思いますが、遷移元と遷移先を矢印で繋いで行けばOKです。
矢印が付いてなくてSTARTでも無いものはメニューなどから直接起動する画面です。
※今回はBottomNavigationViewから起動します。

Activityに設定

ActivityのLayout.xmlを作る時にFragmentの描画エリアを
NavHostFragmentにします。
navigationの定義が1つなら何もしないで完了です。
スクリーンショット 2018-12-19 17.39.56.png
2つ以上のnavigation定義がある場合や上手くいかなかった場合はnavGraphを設定してあげます。

Fragmentにパラメータを渡したい

スクリーンショット 2018-12-21 17.06.51.png
1. パラメータを受け取りたいFragmentを選択
2. 右端のArgumentsをクリック
3. ダイアログに必要事項を設定

渡す側
class NaviViewModel: ViewModel() {

    fun onClickButton(view: View) {
        val bundle = Bundle().apply { 
            putInt("ID", 1)
        }
        view.findNavController().navigate(R.id.action_naviFragment_to_resultFragment, bundle)
    }
}
受け取る側
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidSupportInjection.inject(this)
    val id = arguments?.getInt("ID")
}

Navigation.xmlで引数のName指定などありますが、
実行時(コンパイル時も)チェックされたりしないので、
人間が頑張るのは変わらないです。
※書かなくてもパラメータ渡せるし、デフォルト値が無ければ無駄な作業な気がしてます。

BottomNavigationViewと連携したい

※BottomNavigationViewとの連携がいらないなら以下の項目は不要です。

res/menu配下にBottomNavigationView用のリソースを作ります。

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/main_navigation"
    app:startDestination="@id/reposFragment">
    <fragment
        android:id="@+id/reposFragment"
        android:name="sobaya.app.aac.ui.main.repos.ReposFragment"
        android:label="ReposFragment" />
    <fragment
        android:id="@+id/reposDbFragment"
        android:name="sobaya.app.aac.ui.main.repos_db.ReposDbFragment"
        android:label="ReposDbFragment" />
    <fragment
        android:id="@+id/naviFragment"
        android:name="sobaya.app.aac.ui.main.navi.NaviFragment"
        android:label="NaviFragment" >
        <action
            android:id="@+id/action_naviFragment_to_resultFragment"
            app:destination="@id/resultFragment" />
    </fragment>
    <fragment
        android:id="@+id/resultFragment"
        android:name="sobaya.app.aac.ui.main.navi.result.ResultFragment"
        android:label="ResultFragment" />
</navigation>

ついでにnavigationの定義

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/main_navigation"
    app:startDestination="@id/reposFragment">
    <fragment
        android:id="@+id/reposFragment"
        android:name="sobaya.app.aac.ui.main.repos.ReposFragment"
        android:label="ReposFragment" />
    <fragment
        android:id="@+id/reposDbFragment"
        android:name="sobaya.app.aac.ui.main.repos_db.ReposDbFragment"
        android:label="ReposDbFragment" />
    <fragment
        android:id="@+id/naviFragment"
        android:name="sobaya.app.aac.ui.main.navi.NaviFragment"
        android:label="NaviFragment" >
        <action
            android:id="@+id/action_naviFragment_to_resultFragment"
            app:destination="@id/resultFragment" />
    </fragment>
    <fragment
        android:id="@+id/resultFragment"
        android:name="sobaya.app.aac.ui.main.navi.result.ResultFragment"
        android:label="ResultFragment" />
</navigation>

android:idを両方とも同一にします。
BottomNavigationViewのどのメニューでどのFragmentをキックするかを指定してあげます。

Activityで最後の仕上げ

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        navigation.setupWithNavController(Navigation.findNavController(this, R.id.main_contents))
        navigation.setOnNavigationItemSelectedListener { item ->
            NavigationUI.onNavDestinationSelected(item, Navigation.findNavController(this, R.id.main_contents))
        }
    }

navigationはBottomNavigationViewのidです。

サンプルソース

https://github.com/sobaya-0141/aac