Jetpack Composeの画面遷移
NavControllerを使用して、Composable間の画面遷移を行います。
環境
AndroidStudio:Flamingo | 2022.2.1 Patch 2
OS:macOS
Step1.ライブラリの追加
執筆時点(2023/6/28)での最新は2.6.0です。
navigation-composeを追加します。
dependencies {
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3'
implementation 'androidx.navigation:navigation-compose:2.6.0'
}
Step2.トップ画面と遷移先画面を作成
トップ画面には、遷移先画面へ移動するためのボタンを一つ作ります。
遷移先画面には、JetpackComposeのチュートリアルで作成したメッセージ一覧画面を流用します。
- トップ画面
ボタンを画面の真ん中に表示しています。
IconButtonは、カスタムComposeです。
@Composable
fun TopScreen(onNavigateToConversation: () -> Unit) {
Surface(modifier = Modifier.fillMaxSize()) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(8.dp),
verticalArrangement = Arrangement.Center,
) {
IconButton(label = "Greeting", onClick = onNavigateToConversation)
}
}
}
- 遷移先画面
@Composable
fun ConversationScreen() {
Surface(modifier = Modifier.fillMaxSize()) {
Conversation(SampleData.conversationSample)
}
}
Step3.MainActivityに遷移情報を追加する
画面遷移は、navController.navigation("画面名")で行います。
画面名は、文字列直書きでいいんですが、個人的に、重複と文字列直書きがいやなので、enum classを作成して、そのnameプロパティを指定しています。
setContent {
ComposeTutorialTheme {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Nav.TopScreen.name) {
composable(route = Nav.TopScreen.name) {
TopScreen(
onNavigateToConversation = { navController.navigate(Nav.ConversationScreen.name) },
)
}
composable(route = Nav.ConversationScreen.name) { ConversationScreen() }
}
}
}
enum class Nav {
TopScreen,
ConversationScreen,
}
いざ実行
最初にボタン一つの画面が表示され、ボタンを押すと遷移先画面が表示されます。コードはこちら
Step4.引数を渡す
トップ画面から遷移先画面に移動する際に、引数を渡します。
例として、タイトルとして表示する文字列と日時のミリ秒を渡し、遷移先画面の一番上に表示させてみます。
トップ画面から遷移先画面を呼び出す際、navController.navigateに引数として使用するroute名に「route名+"/"+引数+"/"+引数...」を指定します。(この値はURIと同じエスケープが必要です)
遷移先画面では、route名の変更(引数の追加)、引数の定義を行います。
型定義を省略した場合、すべて文字列として扱われます。
composable(route = Nav.TopScreen.name) {
val title = URLEncoder.encode("/\\ Conversationタイトル /\\", "UTF-8")
val timeInMillis = System.currentTimeMillis()
TopScreen(
onNavigateToConversation = {
navController.navigate("${Nav.ConversationScreen.name}/$title/$timeInMillis")
},
)
}
composable(
route = "${Nav.ConversationScreen.name}/{title}/{time}",
arguments = listOf(
navArgument("title") { type = NavType.StringType },
navArgument("time") { type = NavType.LongType },
),
) { backStackEntry ->
val title = URLDecoder.decode(backStackEntry.arguments?.getString("title") ?: "", "UTF-8")
val timeInMillis = backStackEntry.arguments?.getLong("time")
ConversationScreen(title, timeInMillis)
}
いざ実行
遷移先画面の一番上に、文字列と数値(日時のミリ秒)が表示されました。コードはこちら