LoginSignup
27

More than 3 years have passed since last update.

Navigationを使ったアプリ開発

Posted at

はじめに

Navigationは、Android Jetpackに含まれているコンポーネントで、FragmentやActivityを用いた画面遷移を視覚的に管理することができます。
画面遷移を視覚的に管理することができ、遷移時の値渡しを型安全で渡すことができるという特徴などもあるので、使い方を確認してみようと思います。

Navigationの特徴

Navigationには、以下のような特徴があります。

  • Fragmentで画面遷移を実装する場合は、FragmentTransactionの処理をNavigationが行ってくれる。
  • 進む、戻るのアクションを正しく処理することができる。
  • Navigation Graphを使用し、画面遷移を視覚的に管理することができる。
  • Navigation Graphは、Navigation Editorで簡単に作成・管理することができる。
  • 遷移する際のアニメーションを簡単に設定することができる。
  • Navigation中は型安全で値を渡すことができる。

基本的には、Intentで行っていた画面遷移の管理と同じことを行うことができるようです。

Navigationの原則

Navigationには以下の5つの原則があります。
Navigationは、この原則を守って使用する必要があります。
原文は、こちらです。

  • 開始する画面は必ず固定されている必要がある。
  • 画面は、Navitaion stackを介して表示される必要がある。
  • Upボタンでアプリを終了させてはいけない。
  • アプリ内のタスクでは、UPボタンもBackボタンも同一の動きをする。
  • 同じ宛先へのディープリンク及びナビゲーションは常に同じスタックを生成する。

Navigationコンポーネントに含まれるアイテム

Navigationコンポーネントには、Navigationを使用するためのいくつかのアイテムが含まれています。
詳細は実際にNavigationを使用するまでの手順中にまとめるているので、この章では各アイテムの概要だけを説明します。

Navigation Graph

NavigationGraphは、Navigtionに含まれる画面や、画面遷移などがまとめられたファイルです。
このファイルは、resフォルあ配下にnavigationフォルダを作成し、そのフォルダ内にxmlファイルを作成し定義します。

NavHostFragment

これは遷移の元となる画面のレイアウトに追加する特別なウィジェットです。
画面遷移は、このFragment内のレイアウトを入れ替えて実現します。

NavController

NavControllerは、NavigationGraph内の現在の位置を追跡するためのオブジェクトです。
NavigationGraph内を移動する際に、NavHostFragment内のコンテンツを遷移先のアイテムに交換します。

以上がNavigationコンポーネントで実際に使用するレイアウト、ウィジェット、オブジェクトです。

Navigationの追加

まずは、プロジェクトにNavigationを追加します。

Navigation Editorの有効化

プロジェクトにNavigationを追加する前に、NavigationではNavigationEditorを使用して画面遷移を管理するため、設定からNavigationEditorを有効に設定しておきます。

Android Studioのメニューから以下のように選択します。

File > Android Studio > Preferences

その後、左の一覧からExperimentalカテゴリを選択し、EditorのEnable Navigation Editorを選択したあとに、Android Studioを再起動します。

プロジェクトへのNavigationの追加

プロジェクトへNavigationを追加するためには、build.gradleのdependenciesに、Navigationコンポーネントを追加します。
今回は、Navigation内でFragmentを使用するため、以下の2つを追加します。
また、Kotlinを使用しているため、KTXを使用しています。

dependencies {
  implementation "android.arch.navigation:navigation-fragment-ktx:1.0.0"
  implementation "android.arch.navigation:navigation-ui-ktx:1.0.0"
}

追加後にgradleを同期します。
同期が完了すればNavigationを使用するための事前準備は完了です。

Navigation Graphの作成

次にNavigationGraphを追加していきます。
NavigationGraphは、Navigationを扱うためのファイルで、NavigationEditorを使用して、画面遷移、渡す値などを設定することができます。
実態としては、他のレイアウトファイルと同様で、xmlファイルです。

プロジェクトのresフォルダで右クリックし、開いたメニューから以下のように選択して、リソースファイルの作成ダイアログの表示させます。
New > Android Resource File

リソースファイル作成ダイアログのFile nameフィールドにファイル名を入力します。
今回の説明では、NavigationGraphのファイル名を「nav_graph」という名前にします。
名前は自由につけられるので、今後の手順で「nav_graph」が出てきた際には、自分でつけたファイル名に読み替えてください。

次に、Resouce typeの項目からNavigationを選択します。

その他のフィールドは、特に変更する必要はないので、変更がしたい場合は、各自で変更してください。

OKを選択することでNavigation Graphファイルがnavigationフォルダ下に作成されます。
また、navigationフォルダは、NavigationGraphと同時に自動で作成されます。

NavHostFragmentの追加

次に、起動時に表示される画面のレイアウトにNavHostFragmentを追加します。

NavHostFragmentは、Navigationを使用するために必要な特別なFragmentで、NavigationのデフォルトのNavHostです。
Navigation内での画面遷移は、このFragmentを切り替えながら実現していきます。
基本的には起動時に使用するActivityのレイアウトに以下のようなfragmentを追加します。(ConstraintLayoutを使用しています)

    <fragment
        android:id="@+id/nav_host_fragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"

        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

重要なのは、以下の部分です。

        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

これらパラメータを指定することで、このfragmentをNavHostFragmentとして扱うことができます。
app:navGraphに使用するNavigationGraphを渡すことで、このFragment内でNavigationによる画面遷移を行うことができるようになります。

Navigation Editorについて

Navigation Graphを開くと、Navigation Editorが開きます。
Navigation Editorは、NavigationGraphを扱う専用のエディタで、基本的にはこのエディタを使用してNavigationのそれぞれの設定を行っていきます。

通常のレイアウトのエディタと同じく、NavigationGraphにもDesignタブと、Textタブが用意されています。
それぞれを切り替えることで、NavigationEditorとxmlファイルを表示することができます。

Navigation Editorの画面構成は単純で、XcodeのStoryBoardとも似ています。
エディタは、以下のような画面構成をしています。

: 追加した画面が一覧で表示される部分です。
: 視覚的に表示されたNavigation graphです。この部分を操作して、画面遷移などを実装していきます。
: ②で選択した画面に関連付けられた属性が表示されます。画面への詳細な設定は個々で行います。

Navigation Editorへの画面の追加方法

NavigationEditorを使用して画面を追加するには、画面上部の以下のボタンから追加します。

image.png

このボタンを選択すると、以下のような画面一覧が表示されます。

image.png

この一覧から一つ選択すると、NavigationEditorに指定した画面を追加することができます。
すでに生成されているFragment以外を使用したい場合は、Create new destinationを選択することで新しいFragnemtを生成するためのダイアログが表示されます。

NavigationEditorに追加した画面同士を操作することで、画面遷移や値渡し、遷移時のアニメーションの設定を行うことができます。

起動時に表示されるFragment

アプリ起動時に表示されるFragmentには、家のアイコン image.png が表示されています。
開始位置の設定は、NavigationGraphのapp:startDestination属性で指定されています。

画面遷移の追加方法

Navigationでは、画面遷移をNavigationEditor上で、視覚的に管理することができます。
その追加方法を説明します。

actionの生成

Navigationでは、画面遷移をactionとして扱います。
actionを生成するためには、Navigation Editor内で画面と画面同士を接続します。
遷移元となる画面を選択すると、枠の右側が○になっています。

image.png

この○を引っ張って、遷移先の画面にドラッグします。
するとNavigationEditor上の画面同士が矢印で繋がれます。

image.png

この矢印が、actionとして定義されており、自動的にIDが振られます。
IDはデフォルトで、action_遷移元Fragment名_to_遷移先Fragment名となっています。

Textタブを選択し、xmlファイルを確認すると、遷移元のFragment内に以下のようなactionが定義されています。

image.png

actionを追加した直後に自動生成されるコードには、IDと遷移先の情報(destination)のみが定義されています。
その他、actionには、画面遷移時のアニメーションなどの情報を追加していきます。(画面遷移時のアニメーションの設定は後述します。)

actionの使用

actionは、定義しただけでは何も行いません。
Fragmentなどの実装の中で、NavigationControllerにactionを渡すことで、画面遷移の処理を実行させることができます。

NavigationControllerを呼び出すためには、
KTXに含まれている以下の拡張関数のnavigate()を使用すると楽です。
引数には、実行したいactionのIDを渡します。

Fragment.findNavController()
View.findNavController()
Activity.findNavController()

例えば、ボタンを押された際に画面遷移するようにする場合は、ButtonのClickListener内に以下のようなコードを追加します。

button.setOnClickListener {
    findNavControlelr().navigate(R.id.action_id)
}

これで、ボタンがタップされた際に、画面遷移の処理が実行されます。

画面遷移時の値渡し

Navigationでの画面遷移時でも、もちろん値渡しを行うことが可能です。
画面遷移時を値を渡したい場合は、まずNavigationGraphを操作します。
値が渡される方のFragmentを選択すると、AttributesにArgumentsという項目が表示されます。
ここに、渡したい値の設定を追加していきます。
image.png

まず、Argumentsの+ボタンをタップします。
すると、以下のようなダイアログが表示されます。
image.png

ここにそれぞれ設定したい値を入力・選択していきます。

  • Name: パラメーター名
  • Type: パラメーターの型
  • Nullable: Nullを許容するか
  • Default Value: デフォルト値

今回は、"inputText"というパラメーター名のString型で、nullを許容しない、デフォルトが空文字の値を渡せるように設定したいと思います。

設定は以下のようになります。
image.png

設定を行ったらAddを選択することで、Argumentを追加できます。

実際に値を渡すには、遷移元の処理で、画面遷移を行う際に、navigate()にパラメーターとして追加する必要があります。
Bundleで渡す方法が一番簡単なのですが、パラメーター名や型が明瞭ではないので、今回はSafeArgsを使用します。

SafeArgsの追加

まずは、SafeArgsをプロジェクトに追加します。

gradleファイルに以下の内容を追加します。

buildscript {
    repositories {
        google()
    }
    dependencies {
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.0.0-rc02"
    }
}

今回は、Kotlinしか使っていないのでこちらを追加します。

apply plugin: "androidx.navigation.safeargs.kotlin"

Javaのみもしくは、JavaとKotlinを含んでいる場合は、こちらを追加します。

apply plugin: "androidx.navigation.safeargs"

これで、SafeArgsをプロジェクトに追加できます。

値渡し処理の実装

追加したSafeArgsを使用し、値を渡す処理を実装します。

以下ように実装します。

// 入力された文字列の取得
val inputText = secondFragmentEditText.text.toString()
val action = SecondFragmentDirections
    .actionSecondFragmentToArgumentFragment(inputText)

findNavController().navigate(action)

SecoundFragmentDirectionsというのは、自動的に生成されるクラスです。
今回は、遷移元がSecondFragmentなので、そこに"Directions"をあわせただけの名前になっています。

このクラスには、actionの情報が含まれているため、actionにつけられているIDの、"action_secondFragment_to_argumentFragment"をキャメルケースにしたメソッドが作られています。
このメソッドは、引数に遷移先のArgmentsの情報を持っています。
そのため、遷移先のArgmentsのパラメーター名および型を確認しながら渡す値を設定することができます。

受け取り側の実装

渡された値を実装します。

val args: ArgumentFragmentArgs by navArgs()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    argumentFragmentTextView.text = args.inputText
}

ArgumentFragmentArgsというクラスは、こちらも自動生成されるクラスです。
ArgumentFragmentと"Args"をあわせた名前になっています。

navArgs()というのは、ktxに含まれているもので、Argmentsの取得を簡単に行ってくれています。
ArgumentFragmentには、Argmentsに設定した"inputText"が含まれているので、値が渡されていれば取得することができます。
上記の例では、取得したinputTextの値をTextViewに設定しています。

ktxを使用していない場合は、ArgumentFragmentArgsを自分で生成する必要があるのですが、取得できるargumentがnullableなため、処理がめんどくさくなってしまうので、なるべくktxを使用すると良いと思います。

ktxを利用しない場合のArgumentFragmentArgsの取得方法

val args = ArgumentFragmentArgs.fromBundle(arguments!!)
argumentFragmentTextView.text = args.inputText

画面遷移のアニメーションの設定

Navigationでは、設定を行わなければ、遷移時にアニメーションはありません。
予め用意されている遷移のアニメーションもあるのですが、自分でアニメーションを作成し、使用することも可能です。

レイアウトからのアニメーション設定

遷移時のアニメーションを動的に設定する必要がない場合は、レイアウトから設定が可能です。

Actionを選択すると、AttributesにAnimationsという項目が表示され、
Enter, Exit, Pop Enter, Pop Exitという4項目を設定することができます。

image.png

設定可能な項目のそれぞれの役割は以下のようになっています。

  • 新しい画面に遷移する際のアニメーション

    • Enter
      • 遷移処理発生時に、遷移先の画面が実行するアニメーション
    • Exit
      • 遷移処理発生時に、遷移元の画面が実行するアニメーション
  • 画面がスタックから削除される際のアニメーション

    • Pop Enter
      • 前の画面に戻る際に、戻った際に表示される画面が実行するアニメーション
    • Pop Exit
      • 前の画面に戻る際に、現在表示されている画面が実行するアニメーション

この項目にそれぞれのアニメーションファイルを設定していくことで、遷移時にアニメーションが実行されます。
デフォルトで用意されているアニメーションを以下のように設定することで、新しい画面に遷移する際は、画面が右側から出てくるように見え、戻る際は画面が右側に戻っていくように見えるアニメーションを設定することができます。

スクリーンショット 2019-03-13 10.34.59.png

遷移時のアニメーション設定は、actionに紐付けられるため、xmlファイルを確認すると、以下のように項目が追加されています。

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

コードからのアニメーション設定

遷移時のアニメーションを動的に変更したい場合は、コードからアニメーションを追加することも可能です。

コードから追加する場合は、遷移処理を行う際に、NavOptionを生成し渡すことで、アニメーションを設定することができます。

val navOption = navOptions {
                anim {
                    enter = R.anim.nav_default_enter_anim
                    exit = R.anim.nav_default_exit_anim
                    popEnter = R.anim.nav_default_pop_enter_anim
                    popExit = R.anim.nav_default_pop_exit_anim
                }
            }
findNavController().navigate(
    R.id.action_firstFragment_to_fourthFragment,
    null,
    navOption)

設定に関しては、レイアウトから追加する場合と同様で、enter, exit, popEnter, popExitにそれぞれの動作時に実行したいアニメーションを設定していくだけです。

まとめ

画面遷移の情報が視覚的に確認できるので、Intentでの遷移よりも、ミスが減り、どこの画面から遷移してきているかも確認しやすいと思います。
型安全で値を渡せることや、遷移時のアニメーションを設定しやすいことも大きなメリットだと思います。

Intentでの画面遷移方法からはやり方が大きく変わるので、なかなかNavigationに手が出ないという人もいるかと思いますが、記事を読んでいただければ分かる通り、難しい部分は全く無いので、使って見るのも良いかと思います。
あとは、使っていきながら使いやすいところ使いにくいところを見つけて行ければと思っています!!

今回の記事をまとめるために作成したNavigationのサンプルは、GitHubにおいてあります。
https://github.com/m-kikuchi777/navigation_sample

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
27