Jetpack Composeにおけるカスタムのアノテーションを作成してUI確認の効率を高める

# 概要
AndroidのJetpack ComposeにはUIをAndroid Studio上で確認することが出来るPreviewという機能が存在しています。こちらを利用するとエミュレータや実機にビルドせず、UIの見た目を確認することが出来ます。そのため、開発の効率が向上します。デザイナーとの対面での確認の際にもすぐに反映されるため、すぐに確認することが出来てとても便利です。今回はPreviewの機能をより便利に利用する方法を書きます。

# Previewの利用方法
Jetpack ComposeではComposableの関数に＠Previewを付けることによって、Android Studio上のPreview画面でUIを確認することが出来ます。Previewにはいくつかの引数が存在しています。まずその引数について説明していきます。

### `@Preview` アノテーションの引数一覧

| 引数名             | 型           | 説明                                                                                                                                       |
|--------------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------|
| `name`             | String    | Preview画面で表示される名前|
| `group`            | String    | Previewのグループ名を指定。同じグループに属するPreviewをまとめて表示可能 |
| `apiLevel`         | Int      | レンダリング時に使用するAPIレベルを指定                                                                                                 |
| `widthDp`          | Int       | レンダリング時の最大幅（dp単位）を指定                                                                                                 |
| `heightDp`         | Int       | レンダリング時の最大高さ（dp単位）を指定                                                                                              |
| `locale`           | String    | 使用するロケールを指定（例: `ja-JP`）                |
| `fontScale`        | Float     | フォントスケールを指定                                |
| `showSystemUi`     | Boolean   | `true`の場合、デバイスのステータスバーやアクションバーを表示              |
| `showBackground`   | Boolean   | `true`の場合、デフォルトの背景色を表示                                                                                                 |
| `backgroundColor`  | Long      | 背景色を32ビットのARGBカラーで指定                                                                                 |
| `uiMode`           | Int       | `android.content.res.Configuration.uiMode`に基づいたUIモードのビットマスク（例: `UI_MODE_NIGHT_YES`でダークモード）                                                                   |
| `device`           | String    | 使用するデバイスを指定（例: `spec:width=1080px,height=1920px,dpi=420`）。利用可能なデバイスはAndroid Studioで確認可能                   |
| `wallpaper`        | Int      | Android Studioで利用可能なダイナミックテーマ用の壁紙を指定　|

これらの引数を指定することによって、Android StudioのPreviewでの見え方を変更することが出来ます。実際に引数を変更するとどのようになるかをコードを含めて確認すると以下のようになります。

### showBackgroundのみ指定した場合
``` SamplePreview.kt
@Preview(
    showBackground = true
)
@Composable
fun SamplePreview() {
    ComposeSampleTheme {
        Text(
            text = "サンプルテキスト"
        )
    }
}

```
**Preview画面**
<img src ="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199067/0e656af5-538d-a469-909f-3e5eae0edbd9.png">


#### device等を指定した場合

``` SamplePreview2.kt
@Preview(
    showBackground = false,
    locale = "ja-JP",
    showSystemUi = true,
    group = "sample1",
    device = "spec:width=1080px,height=1920px,dpi=420"
)
@Composable
fun SamplePreview2() {
    ComposeSampleTheme {
        Text(
            text = "サンプルテキスト"
        )
    }
}
```
**Preview画面**
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199067/d45cc093-7cf6-0699-8681-ec08655fed4c.png" width=50%>

上記のようにPreviewの引数に値を指定することで見た目を変更することが出来ます。しかし、この際に毎回引数を指定するとコードの量がとても増えてしまいます。そのためにAnnotaionを自分でカスタムして自分が利用したいPreviewを前もって準備しておくことで、複数のPreviewを表示することが出来ます。

## カスタムアノテーションを作成する
1. AnnotationSample.ktファイルを作成する
1. 作成したファイルの中で下記のようにPreviewに引数を指定する

``` AnnotationSample.kt
@Preview(
    showBackground = false,
    locale = "ja-JP",
    showSystemUi = true,
    group = "sample1",
    device = "spec:width=1080px,height=1920px,dpi=420"
)
annotation class CustomPreview
```

上記のように作成したCustomPreviewは下記のように利用することが出来ます。これによりComposableの関数でPreviewを記載するたびに引数を指定する必要がなくなります。

``` SamplePreview.kt
@CustomPreview
@Composable
fun SamplePreview() {
    ComposeSampleTheme {
        Text(
            text = "サンプルテキスト"
        )
    }
}
```

**Preview画面**
<img src ="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199067/f2fcdcaf-1dc1-f963-e33a-3eacd5e9f84f.png" width=50%>


## Multipreview
最後に今まで記載してきた方法をまとめて表示するAnnotationを作成しようと思います。先ほど作成したAnnotationSample.kt内で一つのAnnotationに対して複数のPreviewを登録をすると、同時に複数のPreviewが表示されます。これによって一つのAnnotationで複数の場合でのUI確認が可能です。

### Previewで確認したいこと
- Tabletの場合のUI
- 画面回転した際のUI
- 特定のPhoneでのUI
- FontのScaleが変わった際のUI
---
#### CustomPreviewの定義
``` AnnotationSample.kt

@Preview(
    showSystemUi = true,
    name = "Tablet UI",
    group = "Device Preview",
    device = "spec:width=800px, height=1280px, dpi=276"
)

@Preview(
    showSystemUi = true,
    name = "Landscape UI",
    group = "Device Preview",
    device = "spec:width=1280dp, height=800dp, dpi=276"
)

@Preview(
    showSystemUi = true,
    name = "Pixel 5",
    group = "Device Preview",
    device = "id:pixel_5"
)

@Preview(
    showBackground = true,
    group = "Font Preview",
    name = "Font Scale x1.5",
    fontScale = 1.5f
)

@Preview(
    showBackground = true,
    group = "Font Preview",
    name = "Font Scale x0.5",
    fontScale = 0.5f
)

annotation class CustomPreview
```

#### CustomPreviewの利用
``` SamplePreview.kt
@CustomPreview
@Composable
fun SamplePreview() {
    ComposeSampleTheme {
        Text(
            text = "サンプルテキスト"
        )
    }
}
```

これにより、Android StudioのPreview画面に複数のPreviewが同時に表示をされます。ただ、現状のAnnotationでは、同時に5つのPreviewが表示されてしまうため、比較しにくいという問題も出てきます。そのために、それぞれのPreviewに対して、`group`を指定しています。これを指定することによって、Previewの表示側で特定の`group`のみを表示することが出来ます。

Preview画面左上の部分のAllとなっている部分においてFont Previewを指定します。すると下記のように指定した`group`のみでの比較も行うことが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199067/4339e1ba-c64a-a5af-da36-193c67f39edc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199067/90afff71-50db-7235-14d2-b4e7fadf4c12.png)

### まとめ
UI確認の作業効率を高めるためにJetpack ComposeのPreviewの機能を拡張するためにカスタムAnnotationを作成しました。今回のSampleで利用していたTextだと少し比較が難しいとは思うのですが、普段の業務の中で作成する複雑なUIになるとより業務の効率が高まるかと思っています。自分も確認に必要なPreviewをどんどん増やしていこうと思っています。

### 参考記事

https://developer.android.com/develop/ui/compose/tooling/previews