Diary

Diary

日々学んだことをアウトプットする場として初めてみました

Jetpack Glance で遊んでみた

前回の記事では Jetpack Glance を使って Widget を実際に表示させるところまで行いました。

今回はGlanceAppWidgetを継承させたクラスをいじって、色々と表示を変えて遊んでみようと思います!

[目次]

環境

- compose-version : 1.1.0-beta03
- 使用 glance version : 1.0.0-alpha02
- 検証 android 端末 : pixel3-os12

サイズによって内容を変更する

widget の大きさに応じて表示内容の調整を行いたい場合、SizeModeを override することで実現します。

次のどちらかのパターンで行います。

exact

サイズの変更を検知し、その度に再描画が走ります。

Composable 関数の中で使用するには、LocalSize.currentでサイズを取得します。

class MyWidget(private val name: String) : GlanceAppWidget() {

    // sizeMode を override する
    override val sizeMode = SizeMode.Exact

    @Composable
    override fun Content() {
        val size = LocalSize.current
    }
}    

Responsive

サイズの変更を検知し、用意した値に近いものに設定されます。

設定が変更されると再描画が走ります。

class GreetingsWidget(private val name: String) : GlanceAppWidget() {

    // 使いたいサイズを用意する
    companion object {
        private val SMALL_SQUARE = DpSize(100.dp, 100.dp)
        private val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp)
        private val BIG_SQUARE = DpSize(250.dp, 250.dp)
    }

    // sizeMode を override する
    override val sizeMode = SizeMode.Responsive(
        sizes = setOf(SMALL_SQUARE, HORIZONTAL_RECTANGLE, BIG_SQUARE)
    )

    @Composable
    override fun Content() {
        val size = LocalSize.current
        val context = LocalContext.current

        if (size.height > SMALL_SQUARE.height) {
            Text("xxx")
        }
        ...
    }
}

いろいろな関数で遊ぶ

標準で用意されている関数に何があるか、androidx.glance.まで打って候補として出てくるものを一度眺めてみると良いと思います。

以下、コード例とスクショ(+感想)をメモしておきます

import 時の注意

Jetpack compose とは使用するものが異なるため、import 時には正しいものを選ぶようにしてください。

例えば以下はTextに対する import の候補なのですが、特に compose.uiのものと間違えないよう、きちんと~~.glance.~~となっているものを選択してください。

f:id:kokoichi206:20220128024148j:plain

Box

全体的に compose と似ている。

Box(
    modifier = GlanceModifier
        .fillMaxSize()
        .background(Color.White)
        .cornerRadius(8.dp),
    contentAlignment = Alignment.Center,
) {
    Text(
        text = "おはよう世界",
        style = TextStyle(
            color = ColorProvider(Color.Red),
            fontSize = 36.sp,
        )
    )
}

f:id:kokoichi206:20220128023744p:plain

Image

Box(
    modifier = GlanceModifier
        .fillMaxSize()
        .background(Color.White)
        .cornerRadius(8.dp),
    contentAlignment = Alignment.Center,
) {
    Image(
        modifier = GlanceModifier
            .cornerRadius(5.dp),
        provider = ImageProvider(R.drawable.gan),
        contentDescription = "generated by gan"
    )
}

f:id:kokoichi206:20220128024523p:plain

Column

Column(
    modifier = GlanceModifier
        .wrapContentHeight()
) {
    for(i in 1..10) {
        Text(
            text = "$i"
        )
    }
}

f:id:kokoichi206:20220128025119p:plain

しかしこのままでは 5 以降が切れてしまっている上に、スクロールもできません。

そんな時は、Jetpack Compose でもお馴染みの LazyColumn を使います。

LazyColumn

LazyColumn(
    horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
) {
    items(10) { id ->
        Text(
            text = "$id",
        )
    }
}

左端に寄っちゃってますが、スクロールできるようになっています。

f:id:kokoichi206:20220128025621p:plain

Button

Button には onClick の属性が必須だったため、MainActivity を起動させてみてます。

Button(
    text = "Click me",
    // MainActivity を起動させる。
    onClick = actionStartActivity<MainActivity>(),
)

f:id:kokoichi206:20220128030037p:plain

レスポンシブルな widget 作成

Row, Column, sizeMode などを使い、サイズによって表示内容の変わる widget を作成してみました。今回は sizeMode の override に exact パターンを使っています。

表示されている widget の行数や列数を取得する方法がわからなかったため、途中で汚い計算をしていますがお許しください。

class MyWidget(private val name: String) : GlanceAppWidget() {

    override val sizeMode = SizeMode.Exact

    @Composable
    override fun Content() {
        val size = LocalSize.current

        Column(
            modifier = GlanceModifier
                .background(Color.White)
                .fillMaxSize()
        ) {
            val col = ((size.height - 90.dp) / 100.dp).toInt() + 1
            val row = ((size.width - 57.dp) / 70.dp).toInt() + 1
            Log.d("hoge", "size.width: ${size.width}")
            Log.d("hoge", "size.height: ${size.height}")
            for (i in 1..col) {
                Row(
                    modifier = GlanceModifier
                        .fillMaxWidth()
                        .defaultWeight(),
                ) {
                    for (j in 1..row) {
                        Box(
                            modifier = GlanceModifier
                                .defaultWeight()
                                .fillMaxHeight(),
                            contentAlignment = Alignment.Center,
                        ) {

                            val position = "$j$i"
                            Text(
                                text = position,
                            )
                            // Text or Image で実験をした
//                            Image(
//                                modifier = GlanceModifier
//                                    .size(60.dp),
//                                provider = ImageProvider(R.drawable.gan),
//                                contentDescription = "image generated by gan"
//                            )
                        }
                    }
                }
            }
        }
    }
}

f:id:kokoichi206:20220128031515p:plain

f:id:kokoichi206:20220128031726p:plain

遊んでみての所感

- Jetpack Compose に似ていて楽しい
- Jetpack Compose 用の API とは似ているが異なるものなので、import を慎重に選ぶ
- いちいち XxxProvider を使わないといけなかったり少しめんどい
  - 引数等きちんと確認する
- Widget の更新は効かないので、再度作り直す(削除⇨再度Widget登録)

おわりに

初めての widget 作成にもかかわらず、楽しく作ることができたのは Jetpack さんのおかげだと思います。

beta・安定版になるのを楽しみに待ってます!