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

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

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

詳しくは、YouTube の ライブ情報とウィジェットでアプリを充実させるをご覧ください。

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

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

アプリは AppWidgetManager の setWidgetPreview を使用できます。不正行為を防止し、システムの健全性に関する懸念を軽減するため、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>

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

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

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

Android 11(API レベル 30)以前のウィジェット選択ツールでウィジェットのプレビューを表示できるようにするには、またはスケーラブルなプレビューの代替として、previewImage 属性を指定します。

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

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

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

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

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

ウィジェットでこれらのビューのいずれかを使用している場合、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>