意外と知られていない気がするので、ViewModelで画面引数を受け取る方法をまとめておきます。
AssistedInjectなどの特殊なことも必要なく、かなり簡単にViewModelで画面引数を受け取れます。
受け取る方法
実はViewModelで画面引数を受け取るには非常に簡単で、以下のように SavedStateHandle
から取得できます。
class SampleViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {
val userId: String? = savedStateHandle["userId"]
// ...
}
ViewModelのコンストラクタで SavedStateHandle
を受け取るようにしておくと、画面引数として渡したときと同じキーを使うだけ取得できます。
渡す方法
画面引数を渡す方法に特別なことは不要で、ActivityのIntent、Navigation Component、Navigation Compose、どの渡し方でも SavedStateHandle
で取得することができます。
// Activity Intent
val intent = Intent(this, SampleActivity::class.java).apply {
putExtra("userId", "xxxx")
}
startActivity(intent)
// Navigation Component
val action = SampleFragmentDirections.action("xxxx")
findNavController().navigate(action)
// Navigation Compose
NavHost(navController = navController, startDestination = "start") {
composable("start") {
HomeScreen(
onClick = { navController.navigate("sample/xxxx") }
)
}
composable("sample/{userId}") {
// ...
}
}
Safe Args対応
Navigation Componentを使ってるときにSafe Argsを使うことが多いと思いますが、SavedStateHandle
から引数を取得するときにもSafe Argsのクラスに変換することが可能です。 fromSavedStateHandle
というヘルパーメソッドが生成されるので、それを使うだけで簡単に対応することができます。
class SampleViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {
val args = SampleFragmentArgs.fromSavedStateHandle(savedStateHandle)
// ...
}
Navigation ComposeのType Safe対応
Navigation Composeを使ってる場合は自分でWrapperを実装する感じになります。詳細は以下の公式ドキュメントにまとまっています。実装自体は単純です。
Composeの画面遷移で、前の画面に結果を返す方法についてまとめておきます。
基本的にはFragmentと同じような感じで NavBackStackEntry
の SavedStateHandle
を使用していきます。
結果を返す
ScreenAからScreenBに遷移して、ScreenBでの画面の結果をScreenAに返す処理です。
navController …
Accompanist
に adaptive
というライブラリが追加されました。これを使用して2ペインのレイアウトを組むことができます。この実装方法について解説していきます。
注意: AccompanistはExperimentalなものなので今後変更される可能性があります。
実装方法
build.gradle
は accompanist-adaptive
を追 …
Composeにおいてrecomposition後も状態を保持するために remember
がありますが、画面回転などConfiguration Change後でも状態を保持する rememberSaveable
について解説します。
rememberSaveable
単純な値で rememberSaveable
を使う場合は remember
とほぼ変わりません。
また、 mutableStateOf
も同様に使用できます。
これだけでConfiguration Change後も値を復元してくれます。
使用できる型
rememberSaveable
はすべての型が使用できるわけではありません。
例えば、上記のように独自のクラスを rememberSaveable
で使おうとすると、以下の例外を投げます。
java.lang.IllegalArgumentException: User(name=) cannot be saved using the current SaveableStateRegistry. The default implementation only supports types which can be stored inside the Bundle. Please consider implementing a custom Saver for this class and pass it to rememberSaveable().
rememberSaveable
は最終的に ComponentActivity#onSaveInstanceState
にて状態を保存するため、 Bundle
に保存できるもだけが使用できます。
サポートされてる型は ココのコード で定義されています。
また、MutableState
については特別な処理で対応していて、MutableState
で使われてる型のほうがチェックされます。
rememberSaveable に対応する
rememberSaveable
に対応するにはいくつかの方法があります。
Parcelable
一番簡単な方法は、独自クラスを Parcelable
にするだけです。
これでクラッシュせず rememberSaveable
でも使用可能になります。
Saverの実装
単純に Parcelable
に対応できない場合は Saver
を実装することで対応することもできます。
Saver
は Bundle
に保存できる型に変換して、Bundle
から復元した値を変換する処理を実装します。 実装したものをrememberSaveable
の saver
パラメータに渡すことで対応できます。
MutableState
を使う場合は stateSaver
パラメータのほうに実装した Saver
を渡します。
Android 13からOpt inにて Predictive back gesture
が使用できるようになります。これにより、バックジェスチャー(画面の左から右にスワイプするやつ)でホームに戻るときに予測できるようになります。
どのような感じは以下のドキュメントで確認できます。戻るときにホーム画面が少し見えるような感じになります。
Material 3のColor Systemには Surface tones
というものがあります。この仕様によって想定した色をうまく設定できないなど気づきにくいこともあります。この Surface tones
についてComposeの実装を踏まえて簡単にまとめておきます。
これ書いてる時点ではCompose Material 3はalphaなので今 …