はじめに
Navigation Component を使うと新規登録画面の画面遷移が簡単に実装できると耳にしました。
公式サイトにも実装方法が記載されていますが、なかなか難しかったので記事としてまとめます。
動作環境
この記事の動作環境は以下のとおりです。
Android Studio:4.1.1
Kotln:1.4.21
Open JDK:1.8
compileSdkVersion:30
targetSdkVersion:30
minSdkVersion:23
Navigation Component:2.3.2
目標
以下を目標とします。
- Navigation Component UIで新規登録の画面遷移を実装できる
動作イメージ
こんな動きをする新規登録の画面遷移を Navigation Component で実装したい!!
機能概要
よくある話ですが、アプリをインストールして 新規登録 をタップして、ウィザード形式でユーザ登録などを行います。
登録が完了した画面や登録完了後に戻ってきたログイン画面で戻るボタンなどをタップすると正しい画面遷移ができています。
下図のようなイメージです。
これってどのように実装しているのだろうと不思議に思うこともあります。
Navigation Componentに、公式サイトに実現の助けになるような機能が搭載されています。
この記事では実現方法を説明していきます。
Fragmentの動作
まず、実装方法の前にFragmentの画面やオブジェクトがどのように管理されているか理解して置く必要があります。
Navigation Componentでは、Fragmentの画面はActivityと同じ用にスタックで管理されています。
下図様なイメージです。
そのため、完了画面に遷移したあと、戻るボタンをタップするとデフォルトの動きでは確認画面に遷移していまいます。
これがFragmentの基本的な動作となります。
そのため、完了画面から戻るボタンや戻る機能を追加するときに、Login画面までスタックをクリアする必要があります。
上記の内容を理解した上で、実装方法を確認してください。
実装方法
前提知識
実装方法の前提知識としては、この記事を理解しておいてください。
アクション
画面遷移でスタックをクリアしたい画面にアクションを接続することにより実現可能です。
下図の様なイメージで、完了画面からログイン画面にアクションを接続します。
graphのネスト
デスティネーションが増えていくと、navigationファイルの編集画面が操作しづらくなってしまいます。
なので、機能毎などでgraphをネストするとわかりやすくなります。
1機能のデスティネーションをすべて選択した状態で、「 group into nest graph 」ボタンをクリックします。
操作方法は下図を参照してください。
「 group into nest graph 」ボタンをクリックすると、ネストしたgraphは 角がまるい四角 になります。
ネストしたgraphの詳細を確認したい場合は、 角がまるい四角 をダブルクリックするだけで下図が表示されます。
ネストしたgraphからもとの画面に戻りたい時は、Component Treeで外側をクリックすると元の画面に戻ります。
実際のコードを確認すると、navigationタグがネストしていることが確認できます。
ネストを利用することにして、機能ごとにnavigaitonをまとめられるので便利ですね。
navigationファイルを新規作成してincludeしても同じ事が行なえます。
スタックを指定したFragmentまでクリアする
先に説明した通り、ウィザード形式のように元の画面までスタックをクリアするには以下の手順を行います。
- アクションに設定を追加する
アクションタグの属性に以下の2つを設定します。
- popUpTo属性
- popUpToInclusive属性
最終的に下記のようなアクションになります。
<action
android:id="@+id/action_completeToRegisterUserFragment_to_loginFragment"
app:destination="@id/loginFragment"
app:popUpTo="@id/loginFragment"
app:popUpToInclusive="true" />
popUpTo属性
公式サイトに説明があります。
Navigation ライブラリに対し、navigate() 呼び出しの一環として、バックスタックからいくつかのデスティネーションをポップするように指示します。属性値として、スタック上に残す最も新しいデスティネーションの ID を指定します。
スタックにある、navigationは一番新しいデスティネーションを探し出してくれるみたいですね。
しかし、これだけではうまく動作しません。
popUpToInclusive属性
こちらも公式サイトに説明があります。
app:popUpToInclusive="true" を追加すると、app:popUpTo 内で指定したデスティネーションもバックスタックから削除するように指示できます。
これで古いLogin画面を削除してアクションので指定しているデスティネーションを新規にスタックに乗っけているわけですね。
なるほど、その他の説明もかいてありますが、興味のある方は公式サイトを参照してください。
戻るボタンの処理を変更する
Androidで用意されているソフトウェアやハードウェアの戻るボタンの挙動も修正しなければなりません。
公式サイトに詳しく書かれていますが、どうやら ** OnBackPressedDispatcher#addCallback** で戻るボタンの挙動を変えるみたいです。
実際のコードは以下の通りです。
// 戻るボタンを押下されても、ログイン画面に戻るようにこの画面のライフサイクル中の戻るボタンのコールバックを変更
requireActivity().onBackPressedDispatcher.addCallback(this) {
val navController = findNavController()
val action =
CompleteToRegisterUserFragmentDirections.actionCompleteToRegisterUserFragmentToLoginFragment()
navController.navigate(action)
}
addCallback() メソッドの引数に ライフサイクルオーナーを渡す方法 と 渡さない方法 があります。
違いは以下のとおりです。
方法 | 挙動 |
---|---|
ライフサイクルオーナーを渡す方法 | そのライフサイクルの間、Callbackで指定した戻るボタンの挙動が有効になる |
ライフサイクルオーナーを渡さない方法 | アプリが終了するまで、Callbackで指定した戻るボタンの挙動が有効にになる |
今回のケースでは、ライフサイクルオーナーを渡す方法が正しいとなります。
以上で実装は完了です。
まとめ
Androidアプリでウィザード形式を実装する方法がとても簡単になりました。
Navigation Componentを今まで避けて通ってきてきた私でしたが、今後は積極的に利用したくなりました。