🚀

Glance入門 はじめの一歩 - 1( 一覧を表示するだけ)

2023/11/05に公開

Composeでウィジェットが作れるGlanceが9月に正式リリースされました。

Glance以前のRemoteViewで作るウィジェットを複数作った経験がありますが、とても簡単になった印象があります。
この記事では、単純なウィジェットを作成してみます。

公式サイトに沿って作ってみましょう。

完成版

こんな簡単なウィジェットを作ります。ウィジェット内部で縦スクロールできます。

環境構築

前提条件

  • androidx.glance:glance-appwidget:1.0.0
  • Android Gradle Plugin (AGP) バージョン7.0.0以上
  • androidx.compose.compiler:compilerが依存するKotlinのバージョン。(Release Not)
  • Composeランタイムバージョン1.1.0以上
  • Android Min.SDK21以上

実装

普通にAndroid StudioでNew Project -> Empty Activityとかで作成して、実装をしていけば良いでしょう。

app/build.gradle.kts

app/build.gradle.kts
android {
    compileSdk = 34
・・・
}

dependencies {
    implementation("androidx.glance:glance-appwidget:1.0.0")
    implementation("com.google.android.material:material:1.10.0")
・・・

GlanceAppWidgetクラス

GlanceAppWidgetを継承したクラスを作成します。provideGlance()メソッドをオーバライドして、provideContent()の引数にコンポーザブル関数を渡します。ここで実装したUIがウィジェットに表示されます。
ちなみにここでのLazyColumnはGlanceのコンポーザブル関数です。
LazyColumnは通常のComposeで同名のクラスがありますが、それとは違います。理由は、以前のウィジェットの実装方法で利用してきたAppWidgetsとRemoteViewsの制限に制約されるからです。そのため、Glanceは通常のComposeとは異なるコンポーザブルを使用して実装します。

class MyGlanceAppWidget : GlanceAppWidget() {
    override suspend fun provideGlance(context: Context, id: GlanceId) {
        provideContent {
            Content()
        }
    }
    @Composable
    fun Content() {
        GlanceTheme {
                LazyColumn(
                    modifier = GlanceModifier
                        .fillMaxSize()
                        .padding(16.dp)
                        .appWidgetBackground()
                        .background(GlanceTheme.colors.primaryContainer)
                ) {
                    items(samples.size) { id ->
                        Text(
                            text = "${LocalContext.current.getString(R.string.widget_title)} ${samples[id]}",
                            modifier = GlanceModifier
                                .fillMaxWidth()
                                .padding(8.dp),
                            style = TextStyle(
                                fontWeight = FontWeight.Bold,
                                fontSize = 18.sp,
                            ),
                        )
                    }
                }
            }
        }
    private val samples = (0..5).map { it }
}

もうひとつ、appWidgetBackground()というのは、ウィジェットの親レイアウトに設定する必要があります。この修飾子を持つビューは、1つのウィジェットに1つだけ存在できます。

GlanceAppWidgetReceiverクラス

次にGlanceAppWidgetReceiverを継承したクラスを作成します。ウィジェット自体の作成・更新を実装するクラスです。

class MyGlanceAppWidgetReceiver: GlanceAppWidgetReceiver() {
    override val glanceAppWidget: GlanceAppWidget = MyGlanceAppWidget()
}

xml関連

上記で作成したクラスを AndroidManifest.xml に記述しときます。

AndroidManifest.xml
・・・
        <receiver android:name=".MyGlanceAppWidgetReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/app_widget_list_glance" />
        </receiver>
    </application>

meta-dataで設定している app_widget_list_glance.xmlは以下です。

xml/app_widget_list_glance.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/widget_description"
    android:minWidth="28dp"
    android:minHeight="14dp"
    android:initialLayout="@layout/glance_default_loading_layout"
    android:previewImage="@drawable/ic_launcher_foreground"
    android:previewLayout="@layout/widget_preview_layout"
    android:resizeMode="horizontal|vertical"
    android:targetCellWidth="2"
    android:targetCellHeight="1"
    android:widgetCategory="home_screen" />

<appwidget-provider>でウィジェットのメタデータを設定します。

その他のポイントは、previewImage と previewLayout です。
previewLayoutは、ユーザがウィジェットを配置する前に表示されるレイアウトファイルです。これはGlanceで指定できないのでXMLで作成する必要があります。そして、これは、SDK31以上(OS 12以降)で利用できるものです。そのため、SDK31未満のために同じ機能であるpreviewImageで画像設定する必要があります。
同じようにandroid:targetCellWidthandroid:targetCellHeightはSDK31以上で利用できるので、SDK31未満のためにminWidthminHeightを指定する必要があります。

NewsPicks の Zenn

Discussion