Android Studio

タスクの種類ごとに色分けする

タスクの種類ごとに色分けする

タスクの種類ごとに色分けするには、以下のことを行います。

  1. タスクの種類(カテゴリ)を定義する
    今回はシンプルな例として、タスク入力時に「仕事」「プライベート」「その他」の3つのカテゴリから選択できるようにしましょう。
  2. タスクのデータ構造を変更する
    これまでは String でタスク名を保存していましたが、タスク名とカテゴリの両方を保持できるように、新しいデータクラスを作成します。
  3. カテゴリ選択用のUIを追加する
    TextField の近くに、カテゴリを選択するためのUI(今回は ExposedDropdownMenuBox を使ってドロップダウンメニューのように見せます)を追加します。
  4. リスト表示時にカテゴリに基づいて色を適用する
    LazyColumn で各項目を表示する際に、タスクのカテゴリに応じて背景色を変更します。

具体的な手順

MainActivity.kt ファイルの TodoListScreen 関数を編集し、関連する部分を変更していきます。

1. 必要なimportを追加

ファイルの先頭あたりに、以下を追加してください。(既にあるものもあるかもしれません)

import androidx.compose.material3.ExposedDropdownMenuBox // ドロップダウンメニュー用
import androidx.compose.material3.DropdownMenuItem // ドロップダウンメニューの項目用
import androidx.compose.material3.ExperimentalMaterial3Api // ExposedDropdownMenuBoxで必要
import androidx.compose.ui.graphics.SolidColor // 色の指定方法
import androidx.compose.foundation.background // 背景色設定用
import androidx.compose.ui.unit.Dp // dp指定用
  • TodoCategory: displayName(表示名)と color(色)を持つEnumクラスです。
  • TodoItem: id、text、category を持つデータクラスです。id は後で項目を削除する際に、同じテキストの項目が複数ある場合でも正確に識別できるようにするために入れています。

3. TodoListScreen を修正してカテゴリ選択と色分けを実装する

TodoListScreen 関数を以下のように変更します。

@OptIn(ExperimentalMaterial3Api::class) // ExposedDropdownMenuBoxで必要
@Composable
fun TodoListScreen(navController: NavController) {
    // TodoItemのリストを保持するように変更
    var todoItems by rememberSaveable { mutableStateOf(mutableListOf<TodoItem>()) }
    var newTodoText by rememberSaveable(stateSaver = TextFieldValue.Saver) {
        mutableStateOf(TextFieldValue(""))
    }

    // カテゴリ選択用の状態
    var expanded by remember { mutableStateOf(false) } // ドロップダウンメニューが開いているか
    var selectedCategory by remember { mutableStateOf(TodoCategory.NONE) } // 選択されたカテゴリ

    Column(
        modifier = Modifier.fillMaxSize().padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "ToDoリスト",
            fontSize = 24.sp,
            modifier = Modifier.padding(bottom = 16.dp)
        )

        // Todo項目入力欄
        OutlinedTextField(
            value = newTodoText,
            onValueChange = { newValue -> newTodoText = newValue },
            label = { Text("新しいToDo") },
            singleLine = true,
            modifier = Modifier
                .fillMaxWidth()
                .padding(bottom = 8.dp)
        )

        // カテゴリ選択ドロップダウンメニュー
        ExposedDropdownMenuBox(
            expanded = expanded,
            onExpandedChange = { expanded = !expanded },
            modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp)
        ) {
            OutlinedTextField(
                value = selectedCategory.displayName,
                onValueChange = {}, // 手動での変更はさせない
                readOnly = true, // 読み取り専用
                label = { Text("カテゴリを選択") },
                trailingIcon = { Icon(Icons.Filled.ArrowDropDown, "ドロップダウン") },
                modifier = Modifier.menuAnchor().fillMaxWidth() // メニューアンカーとして設定
            )
            ExposedDropdownMenu(
                expanded = expanded,
                onDismissRequest = { expanded = false }
            ) {
                TodoCategory.values().forEach { category ->
                    DropdownMenuItem(
                        text = { Text(category.displayName) },
                        onClick = {
                            selectedCategory = category
                            expanded = false
                        }
                    )
                }
            }
        }


        // ToDo追加ボタン
        Button(
            onClick = {
                if (newTodoText.text.isNotBlank()) {
                    val newTodo = TodoItem(
                        text = newTodoText.text,
                        category = selectedCategory
                    )
                    todoItems = (todoItems + newTodo).toMutableList()
                    newTodoText = TextFieldValue("")
                    selectedCategory = TodoCategory.NONE // カテゴリをリセット
                }
            },
            modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp)
        ) {
            Text("追加")
        }

        // ToDoリストを表示するLazyColumn
        LazyColumn(
            modifier = Modifier.fillMaxSize()
        ) {
            // itemsの引数をTodoItemのリストに変更
            items(todoItems, key = { it.id }) { item -> // keyを指定することで削除時のアニメーションがスムーズに
                Card(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(vertical = 4.dp),
                    border = BorderStroke(1.dp, Color.LightGray)
                ) {
                    Row(
                        modifier = Modifier
                            .fillMaxWidth()
                            .background(item.category.color) // カテゴリの色を背景色に適用
                            .padding(horizontal = 16.dp, vertical = 8.dp), // Card内のパディング
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.SpaceBetween
                    ) {
                        Text(
                            text = "[${item.category.displayName}] ${item.text}", // カテゴリ名も表示
                            modifier = Modifier.weight(1f)
                        )
                        IconButton(onClick = {
                            // 削除ボタンが押されたときの処理
                            // idを使って正確に項目を削除
                            todoItems = todoItems.filter { it.id != item.id }.toMutableList()
                        }) {
                            Icon(Icons.Filled.Delete, contentDescription = "削除")
                        }
                    }
                }
            }
        }

        Button(
            onClick = { navController.popBackStack() },
            modifier = Modifier.padding(top = 16.dp)
        ) {
            Text("戻る")
        }
    }
}
  • TodoItem のリストを todoItems として保持するように変更しました。
  • ExposedDropdownMenuBox: ドロップダウンメニューのように動作するUIを作成します。
  • selectedCategory: 現在選択されているカテゴリを保持する状態変数です。
  • Button の onClick で、TodoItem のインスタンスを作成し、todoItems リストに追加します。
  • LazyColumn の items で、各 TodoItem の item.category.color を背景色 (.background()) として適用します。
  • items(todoItems, key = { it.id }): key を指定することで、リストの要素が追加・削除された際のアニメーションがスムーズになります(推奨)。
  • 削除ロジックも、item.id を使ってより正確に削除できるように変更しました。

これで、アプリを再実行すると、タスク入力時にカテゴリを選択できるようになり、リストに表示された際にそのカテゴリに応じた背景色が付くようになります!

※Google AI Studioによる回答を参考にしました

目次に戻る