AndroidのUI開発にJetpack Composeを使ってみる（１）

# 前提条件
- Android Studio Arctic Fox以降
- Kotlinの基本的文法

# 導入
Android Studioを開いて**New Project** -> **Empty Compose Activity**を選択しましょう。
ただし古いバージョンのAndroid Studioを使っている場合は該当部分が存在しません。
![スクリーンショット 2021-08-31 20.17.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592867/ffe45768-c19c-4b15-d838-4746503d5757.png)

アプリケーションの情報を決めると以下のようなテンプレートコードが生成されます。(2021/8/31現在)

```kotlin:MainActivity.kt
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    Greeting("Android")
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    ComposeApplicationTheme {
        Greeting("Android")
    }
}
```

ここで重要なのは、

- ``MainActivity`` -> ``onCreate`` -> ``setContent``内にコンポーズ可能な関数から構成されるカタマリを記述する
- ``@Composable``修飾子をつけた関数はコンポーズ可能であるという
- ``@Preview``修飾子をつけた関数に配置したコンテンツがAndroid Studio上でプレビューとしてみられる


ここで以下の説明のため一旦``setContent``内と``MainActivity``外部の２つの``@Composable``関数は消去した状態にします。

```kotlin:MainActivity.kt
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            
        }
    }
}
```

# 方針
``setContent``内が複雑になるのを防ぐため、新しくComposable関数``MyApp``を定義します。UI部品の組み合わせは``MyApp``内部で行って``setContent``には``MyApp``のみを配置するのがオススメです。また、エディタでプレビューを見られるようにするためにPreview関数も作っておきます。

```kotlin:MainActivity.kt
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApp() // コレ以外書かない
        }
    }
}

@Composable
fun MyApp() {
//    ここにUI部品を並べていく
}

@Preview(showBackground = true)
@Composable
fun Preview() {
    MyApp()
}
```

このようにすることで、MyApp関数を編集していくだけで自動的にプレビューとエミュレータないし実機でのデバッグ時に、同じUIテストができるようになります。

#UI部品の配置
後述するUI部品を、並べて配置する際は``Row()``や``Column()``が使えます。ここで使う[UI部品](#UI部品)は後述するので今は流し見してください。

##Row
Composable関数を横並びで表示したい場合は、並べたい部品を``Row()``の内部で与えることで重ならずに表示することができます。

```kotlin
@Composable
fun MyApp() {
//    ここにUI部品を並べていく
    Row() {
        Text(text = "ちくわぶ")
        Text(text = "ちくわ")
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592867/719f5bd9-4aa0-ea3e-748b-e580f174e5db.png)

##Column
UI部品を縦に並べて表示したい時は``Row()``と同様に``Column()``で括ることで実現できます。

```kotlin
@Composable
fun MyApp() {
//    ここにUI部品を並べていく
    Column() {
        Text(text = "ちくわぶ")
        Text(text = "ちくわ")
    }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592867/687d902b-f4ae-e4de-d80e-7a2714cdd017.png)


#UI部品
## Text
画面上にテキストを配置する際は``Text()``を使います。引数に文字列を指定することで画面に表示することができます。これを使って引数wordsの文字を画面に表示する``@Composable PrintText()``を定義しましょう。

```kotlin:
@Composable
fun MyApp() {
//    ここにUI部品を並べていく
    PrintText(words = "おはようございます")
}

@Composable
fun PrintText(words: String) {
    Text(text = words)
}
```
今、``PrintText()``は構成されるComposable部品に``Text()``１つしか持たないので、``MyApp()``にそのまま``Text(words)``を直書きしても構いませんが、後に機能拡張する場合を考慮して別関数にしています。

ここで、画面に表示するためのComposable関数は``MyApp``に並べるのを忘れないようにしてください。実行すると画面左上に下図のような文字が出力されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592867/673aa9dd-7a3f-8219-f1c0-f8149add24c5.png)

よく使う``Text()``のパラメータとして以下のものが存在します。
- ``color`` : テキストの色指定
- ``fontSize`` : テキストのサイズ変更
- ``maxLines`` : テキストの最大表示行数指定

以降でも共通の概念ですが、ここで２つの異なる``Text()``を表示する場合は注意が必要です。

```kotlin
@Composable
fun MyApp() {
//    ここにUI部品を並べていく
    PrintText(words = "おはようございます")
    PrintText(words = "今日はもう寝ます")
}
```

このように``PrintText（）``を並べた場合、位置が指定されていないので２つのテキストが被さってしまい次のように表示されてしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592867/c9276f5b-85e4-1775-422d-ba8236f7dd1a.png)

並べて配置する際は、先述した[UI部品の配置](#UI部品の配置)にある[``Row()``](##Row)や[``Column()``](##Column)を使いましょう。

```kotlin
@Composable
fun MyApp() {
//    ここにUI部品を並べていく
    Column {
        PrintText(words = "おはようございます")
        PrintText(words = "今日はもう寝ます")
    }
}
```

実行結果は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592867/17b8d6ae-9121-11a9-aabc-1b3e86a2f7d1.png)

##TextField, OutlinedTextField
テキスト入力を行いたい場合は``TextField()``や``OutlinedTextField()``が使えます。

```kotlin
@Composable
fun MyApp() {
//    ここにUI部品を並べていく
    Column() {
        TextField(value = "ほげほげ", onValueChange = {})
        OutlinedTextField(value = "ほげほげ", onValueChange = {})
    }
}
```

``OutlinedTextField()``を使う際には、
- ``value`` : 入力エリアの値
- ``onValueChange`` : 値が変化した時の処理
- ``label`` : 入力エリアの題名のようなもの
を引数で与えましょう。(labelはなくても良い)

また、テキストが変更された際に入力中であることを表すために、画面に表示される``value``を変更し、その変更に伴ってUIが変更されるようにしたいです。これは再コンポーズと呼ばれ、今回の``OutlinedTextField()``の場合は以下のように記述するのが良いです。

```kotlin
@Composable
fun PrintTextField() {
    // textが変更されるとPrintTextFieldが再コンポーズ（再描画みたいなもの）される
    var text by remember { mutableStateOf("") } 

    OutlinedTextField(
        onValueChange = { text = it }, // 値が変わったらそれをtextにいれる
        value = text,                  // textの値をvalueに入れる->画面に表示される 
        label = { Text(text = "ここに入力")}
    )
}
```
``remember()``内の``mutableStateOf()``に渡す引数の値は、TextFieldに表示されてる初期値だと思ってもらえれば良いです。

![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592867/42ebdbdb-a1b8-5048-b8d5-34fed012f173.gif)

##Image
画像を表示する簡単な方法として``Image()``があります。前準備として`app`->`res`->`drawable`に貼りたい画像ファイルを置いておきます。

```kotlin
@Composable
fun MyApp() {
//    ここにUI部品を並べていく
    Image(
        painter = painterResource(id = R.drawable.ckwb),
        contentDescription = "プロフィール画像"
    )
}
```
``painterResource()``に与えている引数の`id`は`R.drawable.(ファイル名)`の形です。

#細かなレイアウト指示
##Modifier
``Text()``や``Image()``などComposableな関数には引数に`modifier`を与えることができることが多いです。ここでは細かいレイアウトの指示を行うことができます。

```kotlin
@Composable
fun MyApp() {
//    ここにUI部品を並べていく
    Row {
        DisplayMyImage()  // 画像表示
        ProfileTextArea() // 名前と本文の表示
    }
}

@Composable
fun DisplayMyImage() {
    Image(
        painter = painterResource(id = R.drawable.ckwb),
        contentDescription = "プロフィール画像",
        modifier = Modifier
            .padding(all = 8.dp)
            .size(50.dp)
            .clip(CircleShape)
    )
}

@Composable 
fun ProfileTextArea() {
    Column() {
        PrintName(name = "ちくわぶ")
        PrintBody(text = "ほげほげとふがふがの間")
    }
}

@Composable
fun PrintName(name: String) {
    Text(
        text = name, 
        color = Color.Green,
        style = MaterialTheme.typography.subtitle1,
        modifier = Modifier.padding(all = 4.dp)
    )
}

@Composable
fun PrintBody(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.body2,
        modifier = Modifier.padding(all = 4.dp)
    )
}
```

実行すると以下のようなプロフィールが出力できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592867/c3d4d96b-96cb-f200-d762-f25de401ff5e.png)

#参考
[Jetpack Compose Tutorial](https://developer.android.com/jetpack/compose/tutorial)