Mokelab Blog

#67 Jetpack ComposeでToDoアプリを作る - 各画面のベースを作る

前回はNavigation Composableを導入したので、今回は各画面のベースとなるComposableを作っていきます。

ルートを追加する

アプリで必要な画面は事前にデザインするのが鉄則ですが、今回は練習のToDoアプリなので次の4画面にします。

ルート名を適当に決めてNavHostに登録していきます。詳細画面と編集画面は対象のToDoのIDが必要なので、パスパラメータとして受け取ることにします。

@Composable
fun ToDoApp() {
  val navController = rememberNavController()
  
  ComposeToDoTheme {
    NavHost(navController = navController, startDestination = "main") {
      composable("main") {
        ...
      }
      // 作成画面
      composable("create") {
      }
      // 詳細画面
      composable("detail/{todoId}") {
      }
      // 編集画面
      composable("edit/{todoId}") {
      }
    }
  }
}

各画面のComposableを作る

次は各画面に対応するComposableを追加します。プロジェクトを作るとuiパッケージが作成されているので、その下に各画面用のパッケージを作ることにします。

パッケージ

各パッケージに画面を表すComposableを追加していきます。クラスではないのでいつものノリでクラスを追加しないよう注意しましょう。suffixは「Screen」にするのがどうもよさそうです。

@Composable
fun MainScreen(navController: NavController) {
}
@Composable
fun CreateToDoScreen(navController: NavController) {  
}
@Composable
fun ToDoDetailScreen(navController: NavController, todoId: Int) {  
}
@Composable
fun EditToDoScreen(navController: NavController, todoId: Int) {  
}

なお、Composable関数は関数なので名前を小文字からはじめたくなりますが、大文字ではじめないとLintに怒られます。

Composable関数名は大文字ではじめること

NavHostで使う

各画面に対応するComposableを作ったので、NavHostのところで使うよう修正します。

@Composable
fun ToDoApp() {
  val navController = rememberNavController()
  
  ComposeToDoTheme {
    NavHost(navController = navController, startDestination = "main") {
      composable("main") {
        MainScreen(navController = navController)
      }
      composable("create") {
        CreateToDoScreen(navController = navController)
      }
      composable("detail/{todoId}") { backStackEntry ->
        val todoId = backStackEntry.arguments?.getString("todoId")?.toInt() ?: 0
        ToDoDetailScreen(navController = navController, todoId = todoId)
      }
      composable("edit/{todoId}") { backStackEntry ->
        val todoId = backStackEntry.arguments?.getString("todoId")?.toInt() ?: 0
        EditToDoScreen(navController = navController, todoId = todoId)
      }
    }
  }
}

ルートの引数(todoId)はbackStackEntry.arguments?.getString("todoId")で取得できます。ToDoのIDはIntにする予定なので、Intへの変換を行っています。

型をIntにする

NavHostのルートの引数は何も指定がない場合は文字列としてパースされます。今回のように数値のみを想定している場合、次のようにargumentsを指定することで数値としてパースさせることができます。

composable(
  "detail/{todoId}",
  arguments = listOf(navArgument("todoId") { type = NavType.IntType })
) { backStackEntry ->
  val todoId = backStackEntry.arguments?.getInt("todoId") ?: 0
  ToDoDetailScreen(navController = navController, todoId = todoId)
}

ここまで作業したものはこちらにあります。

本サイトではサービス向上のため、Google Analyticsを導入しています。分析にはCookieを利用しています。