ウィジェット選択ツールにプレビューを追加する

アプリのウィジェット選択ツールのエクスペリエンスを改善するには、Android 15 以降のデバイスでは生成されたウィジェットのプレビューを、Android 12 ~ Android 14 のデバイスではスケーリングされたウィジェットのプレビュー(previewLayout を指定)を、それ以前のバージョンでは previewImage を提供します。

生成されたウィジェット プレビューを使用すると、ウィジェットの動的でパーソナライズされたプレビューを作成できます。このプレビューは、ユーザーのホーム画面に表示されるウィジェットの様子を正確に反映します。Android 15 以降では、プッシュ API を介して提供されます。つまり、アプリはウィジェット ホストから明示的なリクエストを受け取ることなく、ライフサイクルの任意の時点でプレビューを提供します。

詳しくは、YouTube の Enrich your app with live updates and widgets をご覧ください。

生成されたプレビューを追加する

Android 15 以降のデバイスで生成されたウィジェットのプレビューを表示するには、まずモジュールの build.gradle ファイルで compileSdk の値を 35 以上に設定して、ウィジェット選択ツールに RemoteViews を提供できるようにします。

アプリは AppWidgetManagersetWidgetPreview を使用できます。不正使用を防ぎ、システムの健全性に関する懸念を軽減するため、setWidgetPreview はレート制限された API です。デフォルトの上限は 1 時間あたり約 2 回の通話です。

システムからプレビューを提供するコールバックはないため、アプリで setWidgetPreviews を呼び出すタイミングを決定する必要があります。更新戦略は、ウィジェットのユースケースによって異なります。

  • ウィジェットに静的な情報が含まれている場合や、クイック アクションである場合は、アプリの初回起動時にプレビューを設定します。
  • プレビューは、アプリにデータが入力された後(ユーザーのログイン後や初期設定後など)に設定できます。
  • 選択したケイデンスでプレビューを更新する定期的なタスクを設定できます。

次の例では、XML ウィジェット レイアウト リソースを読み込み、プレビューとして設定します。このスニペットで setWidgetPreview をメソッドとして表示するには、compileSdk ビルド設定が 35 以降である必要があります。

AppWidgetManager.getInstance(appContext).setWidgetPreview(
    ComponentName(
        appContext,
        ExampleAppWidgetReceiver::class.java
    ),
    AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
    RemoteViews("com.example", R.layout.widget_preview)
)

スケーラブルなウィジェット プレビューを追加する

Android 12 以降では、ウィジェット選択ツールに表示されるウィジェットのプレビューはスケーラブルです。これは、ウィジェットのデフォルトのサイズに設定された XML レイアウトとして提供します。以前は、ウィジェット プレビューは静的なドローアブル リソースだったため、場合によっては、ウィジェットをホーム画面に追加したときの表示がプレビューに正確に反映されないことがありました。

スケーラブルなウィジェット プレビューを実装するには、appwidget-provider 要素の previewLayout 属性を使用して、代わりに XML レイアウトを提供します。

<appwidget-provider
    android:previewLayout="@layout/my_widget_preview">
</appwidget-provider>

現実的なデフォルト値またはテスト値を持つ実際のウィジェットと同じレイアウトを使用することをおすすめします。ほとんどのアプリは同じ previewLayoutinitialLayout を使用します。正確なプレビュー レイアウトを作成するためのガイダンスについては、動的アイテムを含む正確なプレビューを作成するをご覧ください。

ユーザーのデバイスが previewLayout をサポートしていない場合にアプリが previewImage を使用するようにフォールバックできるように、previewLayout 属性と previewImage 属性の両方を指定することをおすすめします。previewLayout 属性は previewImage 属性よりも優先されます。

下位互換性のために静的ウィジェット プレビューを追加

Android 11(API レベル 30)以前でウィジェット選択ツールを使用してウィジェットのプレビューを表示する場合、またはスケーラブルなプレビューのフォールバックとして、previewImage 属性を指定します。

ウィジェットの外観を変更する場合は、プレビュー画像を更新します。

この属性は、setWidgetPreview を使用して設定していない場合に、生成されたプレビューのフォールバックとしても使用されます。

動的アイテムを含む正確なプレビューを作成する

図 1: リスト項目が表示されていないウィジェットのプレビュー。

このセクションでは、コレクション ビューListViewGridViewStackView を使用するウィジェット)を含むウィジェットのウィジェット プレビューに複数のアイテムを表示する場合の推奨アプローチについて説明します。これは、生成されたプレビューではなく、スケーラブル ウィジェットのプレビューに適用されます。

ウィジェットでこれらのビューのいずれかを使用している場合、previewLayout で実際のウィジェット レイアウトを直接指定してスケーラブルなプレビューを作成すると、ウィジェット プレビューにアイテムが表示されない場合にエクスペリエンスが低下する可能性があります。これは、コレクション ビューのデータが実行時に動的に設定されるためです。図 1 の画像のような表示になります。

コレクション ビューを含むウィジェットのプレビューをウィジェット ピッカーで適切に表示するには、プレビュー専用の個別のレイアウト ファイルを維持することをおすすめします。この別のレイアウト ファイルには、次のものを含める必要があります。

  • 実際のウィジェット レイアウト。
  • 偽のアイテムを含むプレースホルダ コレクション ビュー。たとえば、複数の偽のリスト項目を含むプレースホルダ LinearLayout を指定することで、ListView を模倣できます。

ListView の例を示すため、別のレイアウト ファイルから始めます。

// res/layout/widget_preview.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="@drawable/widget_background"
   android:orientation="vertical">

    // Include the actual widget layout that contains ListView.
    <include
        layout="@layout/widget_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    // The number of fake items you include depends on the values you provide
    // for minHeight or targetCellHeight in the AppWidgetProviderInfo
    // definition.

    <TextView android:text="@string/fake_item1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginVertical="?attr/appWidgetInternalPadding" />

    <TextView android:text="@string/fake_item2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginVertical="?attr/appWidgetInternalPadding" />

</LinearLayout>

AppWidgetProviderInfo メタデータの previewLayout 属性を指定するときに、プレビュー レイアウト ファイルを指定します。initialLayout 属性には実際のウィジェット レイアウトを指定し、実行時に RemoteViews を構築する際に実際のウィジェット レイアウトを使用します。

<appwidget-provider
    previewLayout="@layout/widget_preview"
    initialLayout="@layout/widget_view" />

複雑なリストアイテム

前のセクションの例では、リストアイテムが TextView オブジェクトであるため、偽のリストアイテムが提供されています。アイテムが複雑なレイアウトの場合、偽のアイテムを提供するのはより複雑になる可能性があります。

widget_list_item.xml で定義され、2 つの TextView オブジェクトで構成されるリスト項目について考えてみましょう。

<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    <TextView android:id="@id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/fake_title" />

    <TextView android:id="@id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/fake_content" />
</LinearLayout>

偽のリスト項目を提供するには、レイアウトを複数回含めることができますが、これにより各リスト項目が同一になります。一意のリスト項目を指定する手順は次のとおりです。

  1. テキスト値の属性のセットを作成します。

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. 次の属性を使用してテキストを設定します。

    <LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
        <TextView android:id="@id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="?widgetTitle" />
    
        <TextView android:id="@id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="?widgetContent" />
    </LinearLayout>
    
  3. プレビューに必要な数のスタイルを作成します。各スタイルの値を再定義します。

    <resources>
    
        <style name="Theme.Widget.ListItem">
            <item name="widgetTitle"></item>
            <item name="widgetContent"></item>
        </style>
        <style name="Theme.Widget.ListItem.Preview1">
            <item name="widgetTitle">Fake Title 1</item>
            <item name="widgetContent">Fake content 1</item>
        </style>
        <style name="Theme.Widget.ListItem.Preview2">
            <item name="widgetTitle">Fake title 2</item>
            <item name="widgetContent">Fake content 2</item>
        </style>
    
    </resources>
    
  4. プレビュー レイアウトのフェイク アイテムにスタイルを適用します。

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" ...>
    
        <include layout="@layout/widget_view" ... />
    
        <include layout="@layout/widget_list_item"
            android:theme="@style/Theme.Widget.ListItem.Preview1" />
    
        <include layout="@layout/widget_list_item"
            android:theme="@style/Theme.Widget.ListItem.Preview2" />
    
    </LinearLayout>