Android Jetpack（Room + Compose）でTodoアプリ作ろう【前編】

みなさんこんにちは！この記事ではAndroid Jetpackに含まれるRoomとComposeを使ってTodoアプリを作りたいと思います。

【前編】（この記事）ではComposeでリスト表示をする部分を実装して、
【後編】ではRoomを使ってデータベースにデータを保存する部分を実装したいと思います。

https://qiita.com/MasashiHamaguchi/items/4402101572af09d55551

今回作成したTodoアプリのソースコードはこちらにあります。（GitHub）

https://github.com/masashihamaguchi/TodoApp-Jetpack

**完成イメージ**

<img alt="device-2022-05-15-165226.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245180/bd4ad59c-af2e-813a-0ae0-f424ce5045ca.gif" width=300>


# Android Jetpackとは？

![Jetpack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245180/6ed9c1cf-1d30-14d0-8b53-17fedf08eb45.png)

Android JetpackはAndroidアプリの開発を行うためのライブラリの集まりで、2018年のGoogle I/Oで発表されました。アプリ開発のためのコンポーネントやツール、ガイダンスが含まれており、下位互換性を持ちながら、Androidバージョンやデバイスに影響されることなく安定したクオリティのアプリを開発することができます。

Android JetpackはUI、Behavior、Foundation、Architectureの4つのカテゴリに分類されます。

![Screen+Shot+2018-05-05+at+11.49.30+AMimage1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245180/ae1e6b78-1f7e-e44c-5c35-b63e8cfac2e6.png)

https://developers-jp.googleblog.com/2018/05/use-android-jetpack-to-accelerate-your.html


# 開発環境
- Android Studio Chipmunk 2021.2.1
- Kotlin: 1.6.10
- Compose Version: 1.1.1
- Room Version: 2.4.2
- targetSDK: 31

# 実装手順

さっそく実装していきましょう！

## 1. プロジェクトを作成する
新しくプロジェクトを作成します。この時`Empty Compose Activity`を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245180/d899597a-92a9-2c94-12ec-d3e4caef457a.png)

アプリ名を入力してプロジェクトを作成します。
まずはRunして、下の画面のように「Hello World!」と表示されればOK！

<img alt="スクリーンショット 2022-04-29 14.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245180/6b43c07c-d7e4-858e-21b1-86d2dad515b9.png" width=300>

## 2. Composeでリストを表示できるようにする

ためしにGreetingの引数の`Android`の文字列を適当な文字列に変えてRunをしてみよう。
文字が変わるはずです。

```kotlin:MainActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TodoAppTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    Greeting("Todo") // Androidを他の文字列に変えてみる
                }
            }
        }
    }
```

ここからリストを表示できるようにしていきます。
Greeting関数の下にMainScreenという関数を作って以下のようなコードを書きます。

```kotlin:MainActivity.kt
@Composable
fun MainScreen(todolist: List<String>) {
    LazyColumn(
        modifier = Modifier.fillMaxSize()
    ) {
        items(todolist) { todo ->
            Text(todo)
        }
    }
}
```

onCreateでサンプルのリストを生成します。
GreetingからMainScreenに書き換えて、引数にリストを渡します。

```kotlin:MainActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TodoAppTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    val todoList = (1..100).map { "タスク ${it}" }
                    MainScreen(todoList)
                }
            }
        }
    }
```

Runするとリストが表示されるはずです。

<img alt="スクリーンショット 2022-04-29 14.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245180/4d979375-833f-ec61-1dd4-50687a9f9a60.png" width=300>

MainScreenを書き換えて画面の構成を整えます。
`Column`を使うと要素を縦に並べることができます。同じように`Row`を使うと要素を横に並べることができます。
画面の上部に`TopAppBar`を使ってAppBarを表示します。画面の下部には`TextField`と`Button`を使ってTodoを入力するUIを作ります。

```kotlin:MainActivity.kt
@Composable
fun MainScreen(todoList: List<String>) {
    Column {
        TopAppBar(
            title = { Text("Todo List") }
        )
        LazyColumn(
            modifier = Modifier.fillMaxWidth().weight(1f)
        ) {
            items(todoList) { todo ->
                Text(
                    text = todo,
                    modifier = Modifier.fillMaxWidth().padding(16.dp)
                )
            }
        }
        Row(
            modifier = Modifier.fillMaxWidth().padding(16.dp)
        ) {
            OutlinedTextField(
                value = "",
                onValueChange = {},
                label = { Text("ToDo") },
                modifier = Modifier.wrapContentHeight().weight(1f)
            )
            Spacer(Modifier.size(16.dp))
            Button(
                onClick = {},
                modifier = Modifier.align(Alignment.CenterVertically)
            ) {
                Text("ADD")
            }
        }
    }
}
```

アプリを実行して下のような画面が表示されればOKです。

<img alt="スクリーンショット 2022-04-29 15.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245180/44a7098c-d768-12ea-1de0-29db6c6f3939.png" width=300>

## 3. リストに動的に要素を追加できるようにする

ここからリストにタスクを追加できるようにしていきます。
`MainScreen`の中に`todoList`と`text`の2つの変数を作ります。この時`MainScreen`の引数は消します。

```kotlin:MainActivity.kt
@Composable
fun MainScreen() {
    var todoList: SnapshotStateList<String> by remember { mutableStateOf(mutableStateListOf()) }
    var text: String by remember { mutableStateOf("") }

    ....
}
```

`OutlinedTextField`を下のように書き換えます。

```kotlin:MainActivity.kt
        ) {
            OutlinedTextField(
                value = text,
                onValueChange = { it -> text = it },
                label = { Text("ToDo") },
                modifier = Modifier.wrapContentHeight().weight(1f)
            )
            ....
```

`Button`コンポーネントをしたのように書き換えます。

```kotlin:MainActivity.kt
            ....
            Button(
                onClick = {
                    if (text.isEmpty()) return@Button
                    todoList.add(text)
                    text = ""
                },
                modifier = Modifier.align(Alignment.CenterVertically)
            ) {
                Text("ADD")
            }
```

`onCreate`内のMainScreeを呼び出している部分の引数も消します。

```kotlin:onCreate
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TodoAppTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    val todolist = (1..100).map { "タスク ${it}" }
                    MainScreen() // 引数を消す
                }
            }
        }
    }
```

アプリを実行してみましょう。
リストにタスクが追加できるようになっているはずです！

<img alt="スクリーンショット 2022-04-29 15.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245180/42d1e961-99b1-ead0-a95f-f0bcc41d97a9.png" width=300>


kotlinファイルだけでUIまで実装することができました！
次回はRoomを使ってデータの保存を実装します。

# 参考資料

https://engawapg.net/jetpack-compose/1442/list/

https://developer.android.com/jetpack/getting-started?hl=ja

https://developer.android.com/jetpack/compose?hl=ja