Jetpack Composeを学ぶ ComposeTutorial

## はじめに
[JetpackComposeチュートリアル](https://developer.android.com/jetpack/compose/tutorial?hl=ja&continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fjetpack-compose-for-android-developers-1%3Fhl%3Dja%23article-https%3A%2F%2Fdeveloper.android.com%2Fjetpack%2Fcompose%2Ftutorial)を学んだ内容を記載してます
（一応[第０回](https://qiita.com/t_hiro2626/items/1d2a679aab94e0db80ad)の続き）
## レッスン１ コンポーズ可能な関数
#### コンポーズ可能な関数とは
- @Composableアノテーションを付けることで宣言可能
- UIの外観とデータの依存関係を指定することによってアプリのUIをプログラムで定義できる関数
- 要素の初期化や親のViewへのアタッチなどを気にしなくて済む


#### テキスト追加
- setContentブロックでコンポーズ可能な関数が呼び出されるアクティビティのレイアウトを定義
- Textは画面上にテキストラベルを表示
 
```.kt
setContent {
    Text("Hello world!")
}
```
#### コンポーズ可能な関数を定義

`@Composable`アノテーションを追加することで関数をコンポーズ可能にできる
```.kt
@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}
```

#### AndroidStudioでプレビュー
- @Previewアノテーションを付けることでAndroidデバイスやエミュレータにインストールせずに確認できる
- @Previewアノテーションはパラメータを受け取らないコンポーズ可能な関数にのみ使用することができる

```.kt
@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
```


## レッスン２ レイアウト
- Composeで定義していくUIは階層状
- コンポーズ可能な関数からコンポーズ可能な関数を呼び出していくことで様々なUIを表現可能
#### 複数テキストの定義
```.kt
data class Message(val author: String, val body: String)

@Composable
fun MessageCard(msg: Message) {
    Text(text = msg.author)
    Text(text = msg.body)
}
```

#### 列を使用する
- Column関数で要素を垂直方向に揃えることができる
- Row関数は水平方向
- Box関数で要素を積み重ねられる

```.kt
@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}
```
#### 画像要素を追加
- Image関数で画像リソースを追加
- contentDescriptionも設定可能

```.kt
Image(
    painter = painterResource(R.drawable.profile_picture),
    contentDescription = "Contact profile picture",
)
```
#### レイアウトを構成
- `Modifier`関数

  - コンポーザブルのサイズ、レイアウト、外観の変更
    - padding,widh,height
    - clip,borderなど
  - クリック可能などのインタラクションを追加
    - clickableなど

```.kt
Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                // 画像サイズ設定
                .size(40.dp)
                // 丸で型取り
                .clip(CircleShape)
        )

        // 要素同士横方向のスペース設定
        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            // テキスト縦方向のスペース設定
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
```

## レッスン３ マテリアルデザイン
Composeはマテリアルデザインの原則をサポート
UI要素の多くは最初からマテリアルデザインを実装

#### マテリアルデザインの使用
- プロジェクトの名前+Theme(例:ComposeTutorialTheme)とSurface関数でをコンポーズ可能な関数をラップ
- マテリアルデザインは`Color`, `Typography`, `Shape`を中心に構成
```.kt
setContent {
    ComposeTutorialTheme {
        Surface(modifier = Modifier.fillMaxSize()) {
            MessageCard(Message("Android", "Jetpack Compose"))
        }
    }
}
```

#### Color
- `MaterialTheme.Colors`を使用
- 必要な場合どこでもテーマの値を使用可能
```.kt
modifier = Modifier
    .size(40.dp)
    .clip(CircleShape)
    // 枠線を描画し、カラー適用
    .border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
```
#### Typography
- `MaterialTheme.typography`をTextに使用
- 活字の設定可能

```.kt
Text(
    text = msg.body,
    // Textに対してbody2を適用
    style = MaterialTheme.typography.body2
)
```
#### Shape
- Surface関数でコンポーズ可能な関数をラップ
- Surface関数に`MaterialTheme.shapes`を使って設定可能
```.kt
// shapes.mediumを適用
Surface(shape = MaterialTheme.shapes.medium, elevation = 1.dp) {
    Text(
        text = msg.body,
        modifier = Modifier.padding(all = 4.dp),
        style = MaterialTheme.typography.body2
    )
}
```

#### ダークテーマを有効
- マテリアルデザインのサポートでダークテーマを処理可能
  - ダークモード有効で自動的に調整
- Preview内でも設定する事で確認可能

```.kt
// 通常モードのプレビュー
@Preview(name = "Light Mode")
// ダークモードのプレビュー
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
```

## レッスン４ リストとアニメーション
アプリ内のあらゆる場所で使われるリストとアニメーションを、Composeを使って簡潔に実装

#### メッセージのリストを作成
- LazyColumn, LazyRowで複数要素を扱う
    - items()でパラメータでListを受け取れる
    - 画面上で表示される要素のみレンダリング

```.kt
@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        // 扱うListを受け取る
        items(messages) { message ->
            // 1つごとの要素に対してComposable関数を適用
            MessageCard(message)
        }
    }
}
```
#### 展開時のアニメーション
展開されているというUI状態を保存をするために`remember`関数と`mutableStateOf`関数を使ってトラッキングを行う
- remember：ローカル状態をメモリに格納
- mutableStateOf：ここに渡された値をトラッキングに用いる

rememberやmutableStateOfなどの状態を扱う関数を使うことで、状態の変更によるUIの自動更新が可能
→これを[再コンポーズ](https://developer.android.com/jetpack/compose/mental-model?hl=ja#recomposition)という
```.kt
// rememberで展開状態を保持
var isExpanded by remember { mutableStateOf(false) }
// 展開状態によって色をアニメーション状に変える変数
val surfaceColor by animateColorAsState(
    if (isExpanded) MaterialTheme.colors.primary else MaterialTheme.colors.surface,
)

// タップによる展開状態を反映
Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
    Text(
        text = msg.author,
        color = MaterialTheme.colors.secondaryVariant,
        style = MaterialTheme.typography.subtitle2
    )

    Spacer(modifier = Modifier.height(4.dp))

    Surface(
        shape = MaterialTheme.shapes.medium,
        elevation = 1.dp,
        // 展開状態でアニメーション状に色が変わる値を代入
        color = surfaceColor,
        // 1dpずつ展開が拡大していくよう設定
        modifier = Modifier.animateContentSize().padding(1.dp)
    ) {
       Text(
           text = msg.body,
           modifier = Modifier.padding(all = 4.dp),
            // メッセージが展開されている時は全体表示
            maxLines = if (isExpanded) Int.MAX_VALUE else 1,
            style = MaterialTheme.typography.body2
        )
    }
}
```

#### 成果物
チュートリアルを最後まで実施して出来上がる成果物がこちら
アニメーション展開可能な、アイコン, 名前, メッセージが要素のメッセージリストが出来上がる
    
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2044482/ce3e6b5d-e11c-c031-c41d-30db75e4070e.gif" width="250">

## まとめ
#### コンポーズ可能な関数とは
- @Composableをつける事で宣言可能な関数
- アプリのUIをプログラムで定義可能

#### コンポーズ可能な関数の種類
- setContent：レイアウトを定義
- Text：テキスト
- Column：縦に要素を並べる 
- Row：横に要素を並べる
- Box：要素を積み重ねる
- Image：画像を扱う
- Modifier：要素の様々な設定
    - コンポーザブルのサイズ、レイアウト、外観の変更
        - padding,widh,height
        - clip,borderなど
    - クリック可能などのインタラクションを追加
        - clickable 
    - アニメーションに関する設定
        - animateContentSize
- プロジェクト名+Theme：マテリアルデザインの適用
    - Color：色
    - Typography：活字
    - Shape：形状
- LazyColumn,LazyRow：リストを表示、itemsで要素を扱う
- remember,mutableStateOf：状態をローカルに保持して再コンポーズに使用
- animateColorAsState：状態によって表示を変える 

#### プレビュー
- @PreviewアノテーションでAndroidStudio状で表示の確認可能
    - ダークモードも確認可能


#### 感想
今回Composeにおける多くの要素を学んだが、まだ慣れておらずxmlの方がどの要素に何があるかを理解しやすいなと思った。（慣れれば変わると期待）
LazyColumnやLazyRowを使ってこれまでRecyclerViewでやっていた事を置き換えるとなった時に、どの程度の複雑さになるかが気になった。
次回は[Compose思想](https://developer.android.com/jetpack/compose/mental-model?hl=ja&continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fjetpack-compose-for-android-developers-1%3Fhl%3Dja%23article-https%3A%2F%2Fdeveloper.android.com%2Fjetpack%2Fcompose%2Fmental-model)を学ぶ予定