Jetpack Compose で画面遷移する仕組みとして Navigation Compose が用意されています。
stable になるまで大きな変更が入るそうですが、1.0.0-alpha01 時点でどのように使うのか、内部でどのようなことをしているのか書いていこうと思います。
実装
セットアップ
dependencies {
implementation "androidx.navigation:navigation-compose:1.0.0-alpha01"
}
ライブラリへの依存を追加します。
画面の定義
@Composeable
fun App() {
val navController = rememberNavController()
NavHost(navController, startDestination = "profile") {
composable("profile") { ProfileScreen(...) }
composable("friends") { FriendsScreen(...) }
}
}
Composable の NavHost
と rememberNavController
で最初の画面や遷移先の画面を設定していきます。
NavHost
内の composable
で設定した文字列をキーに画面へ遷移することになります。
遷移処理
Button(
onClick = {
navController.navigate("friends")
}
) {
Text(text = "Navigate next")
}
NavHostController#navigate
で遷移したい画面の composable
に定義した文字列を渡すことで画面遷移を行います。
前の画面に戻る際は NavHostController#popBackStack
を使います。
遷移時に値を渡す
NavHost(...) {
...
composable(
route = "friend/{friendId}",
arguments = listOf(navArgument("friendId") { type = NavType.StringType })
) {...}
}
NavHost
内の composable
の文字列に渡したい値のプレースホルダーを定義します。
そして arguments
に渡したい値と型の定義をします。
composable(
route = "friend/{friendId}",
arguments = listOf(navArgument("friendId") { type = NavType.StringType })
) { backStackEntry ->
Friend(navController, backStackEntry.arguments?.getString("friendId"))
}
composable
の中で定義した Composable の画面で NavBackStackEntry#arguments
から値を取り出せます。
(Parcelable や Serializable どうするんだろ…)
Navigation Compose の実装をみてみる
内部でどのようにして画面遷移を実現しているのかライブラリのコードをみてみましょう。
public fun NavGraphBuilder.composable(
route: String,
arguments: List<NamedNavArgument> = listOf(),
deepLinks: List<NavDeepLink> = listOf(),
content: @Composable (NavBackStackEntry) -> Unit
) {
addDestination(
ComposeNavigator.Destination(provider[ComposeNavigator::class], content).apply {
val internalRoute = createRoute(route)
addDeepLink(internalRoute)
val argument = navArgument(KEY_ROUTE) { defaultValue = route }
addArgument(argument.component1(), argument.component2())
id = internalRoute.hashCode()
arguments.forEach { (argumentName, argument) ->
addArgument(argumentName, argument)
}
deepLinks.forEach { deepLink ->
addDeepLink(deepLink)
}
}
)
}
NavHost
内の composable
のコードです。
composable
に引数に渡した文字列を createRoute
に渡して、 "android-app://androidx.navigation.compose/$route"
というリンクを生成して DeepLink として設定しています。
値を渡す時にプレースホルダーを使った時点でなんとなく察することができそうですが、Jetpack Navigation の DeepLink の仕組みを使って Jetpack Compose の画面遷移を実現しているようです。
これまでの Jetpack Navigation の知識をそのままに Jetpack Compose でも遷移できるようになっているので、新しく知ることも少なくすみ移行もしやすそうですね。