FURYU Tech Blog - フリュー株式会社

フリュー株式会社の開発者が技術情報を発信するブログです。

Jetpack Composeのプレビュー活用例

はじめに

こんにちは。 ピクトリンク事業部でwebアプリケーション開発を担当している西村です🧑‍💻
今回はJetpack Composeのプレビュー活用例をご紹介しようと思います!

Jetpack Composeのプレビューとは

Jetpack Composeでは@Previewアノテーションを使用することで、Android Studio上でリアルタイムにUIをプレビューできます。
これにより、実機やエミュレータを使わずに素早くUIの確認と調整を行うことができます。
まずは簡単なプレビューの例です。

@Composable
fun Greeting(name: String) {
    Text(
        text = "Hello, $name!",
        color = Color.White
    )
}

@Preview
@Composable
fun GreetingPreview() {
    Greeting(name = "Compose")
}

@Composableアノテーション
@Composableアノテーションを付与した関数はコンポーザブル関数となり、 Jetpack Composeを使用してUI作成が行えます。
他の@Composableアノテーションが付与された関数を呼び出すことができ、
関数を組み合わせることによって複雑なUIを作成していきます。

@Previewアノテーション
@Previewアノテーションを付与したコンポーザブル関数は、 Android Studioのプレビューウィンドウに表示されます。
上記のコードをプレビューウィンドウに表示したものが以下になります。

また以下のように実装を変更するとすぐにプレビューに反映されるため、毎回ビルド時間で待たされることなく実装が捗ります🙌

@Previewアノテーションにパラメータを設定する

@Previewには様々なパラメータがあり、プレビューの表示をカスタマイズできます。

@Preview(showBackground = true, backgroundColor = 0xFFFFFF)
@Composable
fun GreetingPreview() {
    Greeting(name = "Compose")
}
  • showBackground: 背景を表示するかどうか(デフォルトはfalse)
  • backgroundColor: 背景色を指定(16進数のカラーコード)
@Preview(name = "Pixel 4", device = Devices.PIXEL_4)
@Preview(name = "Nexus 7", device = Devices.NEXUS_7_2013)
@Composable
fun GreetingPreview() {
    Greeting(name = "Compose")
}
  • device: プレビューするデバイスの種類を指定
  • name: プレビューの名前を指定
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Dark Mode")
@Composable
fun GreetingPreview() {
    Greeting(name = "Compose")
}
  • uiMode: UIのモードを指定(例:Configuration.UI_MODE_NIGHT_YESでダークモード)
@Preview(showBackground = true, name = "English")
@Composable
fun GreetingPreviewEnglish() {
    Greeting(name = "Compose")
}

@Preview(showBackground = true, name = "Japanese")
@Composable
fun GreetingPreviewJapanese() {
    Greeting(name = "コンポーズ")
}

異なるパラメータを持つ複数のプレビューを作成することで、様々な状態のUIを一度に確認できます。

Compose Multipreview Annotations

先ほどは@Previewに様々なパラメーターをする方法をご紹介しましたが、
毎回コンポーザブル関数に複数のパラメーターを指定するのはとても面倒です。
Compose Multipreview Annotationsを使うことで複数の@Previewをまとめることができます。

今回このようなプロフィールカードを作成してみました。

このUIを作成しているコンポーザブル関数にja/enのlocaleと端末の最大サイズ/最小サイズのプレビューを確認しようとすると、
以下のようなアノテーションになります。

@Preview(showBackground = true)
@Preview(name = "minimum", device = Devices.NEXUS_5)
@Preview(name = "maximum", device = Devices.NEXUS_10)
@Preview(name = "Japanese", locale = "ja")
@Preview(name = "English", locale = "en")
@Composable
fun ProfileCardPreview() {
    ProfileCard()
}

一度だけの設定だけであればいいのですが、おそらく他のコンポーザブル関数にも同じ条件でアノテーションを付与して画面を確認しそうですよね。
その場合は以下のようにCompose Multipreview Annotationsを利用することで1つのアノテーションにまとめてくれます

@Preview(showBackground = true)
@Preview(name = "minimum", device = Devices.NEXUS_5)
@Preview(name = "maximum", device = Devices.NEXUS_10)
@Preview(name = "Japanese", locale = "ja")
@Preview(name = "English", locale = "en")
annotation class MultiLocalePreviews

先ほど定義したMultiLocalePreviewsを設定することでプレビュー画面に正しく表示されます。

@MultiLocalePreviews
@Composable
fun ProfileCardPreview() {
    ProfileCard()
}

コンポーザブル関数に引数が必要な場合

コンポーザブル関数に引数が必要な場合はよくあるかと思います
以下のコードでは先ほどのプロフィールカードの名前と職業を引数で受け取った値を表示するようにしました。

@MultiLocalePreviews
@Composable
fun ProfileCardPreview() {
    ProfileCard(userInfo = UserInfo(name = "Yoshihiro Nishimura", job = "Android Developer"))
}

1ケースだと問題ないのですが、引数の組み合わせで複数プレビュー表示したい場合に同じようなコードが増えてしまいます。
それを解消してくれるのがPreviewParameterProviderです。

class PreviewUserInfoProvider : PreviewParameterProvider<UserInfo> {
    override val values: Sequence<UserInfo>
        get() = sequenceOf(
            UserInfo(name = "Yoshihiro Nishimura", job = "Android Developer"),
            UserInfo(name = "空条 承太郎", job = "iOS Developer"),
            UserInfo(name = "空条 徐倫", job = "UI/UX Designer"),
        )
}

@Preview
@Composable
fun ProfileCardPreview(
    @PreviewParameter(PreviewUserInfoProvider::class) userInfo: UserInfo
) {
    ProfileCard(userInfo = userInfo)
}

テストしたいケースがわかりやすく、スッキリしてますね!
プレビュー画面もちゃんと表示されています👍

最後に

今回はJetpack Composeのプレビュー機能の活用方法をご紹介しました!
プレビュー機能は開発生産性を上げるのはもちろんですが、UIテストにも活用できます。
Previewで表示した画面のスクリーンショットを撮影してVisual Regression Testingを行うことができれば、
より品質の高いプロダクトを提供することができるでしょう!
弊社のプロダクトにはまだそのレベルまで導入することができていないので、
これからどんどん推進していけたらなと思いました⭐️