Navigationを導入する
公式Doc: Navigation
導入
// Kotlin
implementation("androidx.navigation:navigation-fragment-ktx:$nav_version")
implementation("androidx.navigation:navigation-ui-ktx:$nav_version")
// Feature module Support
implementation("androidx.navigation:navigation-dynamic-features-fragment:$nav_version")
// Testing Navigation
androidTestImplementation("androidx.navigation:navigation-testing:$nav_version")
Mavenによると、最新版は2.3.5らしい。
Navigationの構成要素
- Navigation Graph: すべてのDestinationとActionを格納するリソースファイル。アプリ内のパスを示す。
- Destination: アプリ内の様々なコンテンツ領域を示す
- Action: Destination間の論理接続を示し、ユーザーが移動可能なパスを表現する
NavigationGraph追加
res
ディレクトリにNavigationGraph
を追加するには、 New > Android Resource File
でResource type: Navigation
を選択して新規リソースとしてnavigation_graph.xml
を追加する。
-> Navigation Editorが使えるようになった。けどまだ空っぽ。
NavHostをActivityに追加
activityに以下を追加。
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
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"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
-
android:name
はNavHostの実装クラス名 -
app:defaultNavHost="true"
はシステムの戻るボタンをインターセプトできるようになる。NavHostは1つだけデフォルれる。
LayoutEditoerからNaviHostを追加することもできる。LayoutEditor > Palette > Containers > NavHostFragment
疑問: widthとheightはmatch_parentじゃなくて0dpでいいのかな?
ConstraintLayoutはmatch_parent
はmatch_constraints
になってて、設定するには0dpを指定するみたい。
Yukiの枝折- ConstraintLayout
NavGraphにDestinationを追加
NavigationEditor > New Destination > Create new destination
でFragmentのタイプを選んでcreate。
Placeholder Destinationってなに?
プレースホルダを使用して、未実装のデスティネーションを示すことができます。 プレースホルダは、デスティネーションの視覚的な表現として機能します。Navigation Editor 内では、通常のデスティネーションと同様に、プレースホルダを使用できます。
注: アプリを実行する前に、プレースホルダの class 属性を既存のデスティネーションに変更する必要があります。プレースホルダによってコンパイル エラーが発生することはありません。ただし、プレースホルダ デスティネーションに移動しようとすると、アプリはランタイム例外をスローします。
Destinationの構造
項目 | 説明 |
---|---|
id | Destinationを参照する際に使用するid |
Label | ユーザが読むことのできる形式でDestinationの名前が表示される。これはUIに表示させることも可能。(setupWithNavController()を使用してNavGraphをToolbarに接続する場合 )。リソース文字列の使用を推奨。 |
name | 説明無し。Fragmentのpathっぽい |
class | 存在してないが説明あり。関連付けられてるクラス名 |
type | 存在してないが説明あり。実装タイプがFragmentなのかActivityなのかカスタムなのか。型? |
説明がupdateされてなさそうだけど、旧type+class = nameになってる感じか。
NavigationEditorから各Destination(Fragment)のcodeも参照できて便利。
Start Destination
ユーザがアプリを開いた際に最初に表示される画面のこと。家アイコンで指定できる。
指定するとnavGraphのapp:startDestination
に追加されてた。
<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_graph"
app:startDestination="@id/topFragment">
Destinationを接続する
EditorでFragmentをつなぐことで移動先を定義できる。
各画面の共通の移動先としてグローバルアクションを定義することもできる。
Destinationに移動する
移動はNavHost内でNavigationを管理するNavController
を使用して実行される。各NavHostはそれぞれ独自のNavController
を持つ。
// NavControllerの取得
Fragment.findNavController()
View.findNavController()
Activity.findNavController(viewId: Int)
FragmentContainerView を使用して NavHostFragment を作成する場合、または FragmentTransaction からアクティビティに NavHostFragment を手動で追加する場合、Navigation.findNavController(Activity, @IdRes int) からアクティビティの onCreate() で NavController を取得しようとするとエラーになります。NavHostFragment から直接 NavController を取得してください。
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
Safe Args
Destination間を移動する際は、Safe Args Gradle Plugin
の使用が推奨されている。これはDestination間で型安全なNavigationと引数の受け渡しを可能にする。
追加
module build.gradle
buildscript {
repositories {
google()
}
dependencies {
def nav_version = "2.3.5"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
}
app build.gradle
// for Java and Kotlin
plugins {
id 'androidx.navigation.safeargs'
}
// for Kotlin
plugins {
id 'androidx.navigation.safeargs.kotlin'
}
gradle.properties ファイルに android.useAndroidX=true が必要。
Safe Args を有効にすると、このプラグインによって、定義した各アクションのクラスとメソッドを格納するコードが生成されます。各アクションに対し、Safe Args は、アクションの発生元となる送信側デスティネーションごとにクラスを生成します。生成されるクラス名は、送信側デスティネーションのクラス名に「Directions」という語を組み合わせたものになります。たとえば、送信側デスティネーションが「SpecifyAmountFragment」という名前の場合、「SpecifyAmountFragmentDirections」という名前のクラスが作成されます。生成されるクラスには、送信側デスティネーション内で定義されている各アクション用の静的メソッドが格納されます。このメソッドは、定義済みのアクション パラメータを引数として受け取り、NavDirections オブジェクトを返します。このオブジェクトは navigate() に渡すことができます。
override fun onClick(view: View) {
val action =
SpecifyAmountFragmentDirections
.actionSpecifyAmountFragmentToConfirmationFragment()
view.findNavController().navigate(action)
}
値を渡す方法は「Safe Args を使用してタイプセーフにデータを渡す」を参照。