Ajouter des aperçus à votre sélecteur de widgets

Pour améliorer l'expérience de sélection des widgets de votre application, fournissez un aperçu de widget généré sur les appareils Android 15 et versions ultérieures, un aperçu de widget redimensionné (en spécifiant un previewLayout) pour les appareils Android 12 à Android 14, et un previewImage pour les versions antérieures.

Les aperçus de widgets générés vous permettent de créer des aperçus dynamiques et personnalisés de vos widgets, qui reflètent précisément leur apparence sur l'écran d'accueil d'un utilisateur. Pour Android 15 et versions ultérieures, ils sont fournis via une API push, ce qui signifie que votre application fournit l'aperçu à tout moment de son cycle de vie sans recevoir de requête explicite de l'hôte du widget.

Pour en savoir plus, consultez Enrich your app with live updates and widgets (Enrichir votre application avec des infos en direct et des widgets) sur YouTube.

Ajouter des aperçus générés

Pour afficher les aperçus de widgets générés sur un appareil Android 15 ou version ultérieure, définissez d'abord la valeur compileSdk sur 35 ou une version ultérieure dans le fichier build.gradle du module afin de pouvoir fournir RemoteViews au sélecteur de widgets.

Les applications peuvent utiliser setWidgetPreview dans AppWidgetManager. Pour éviter les abus et limiter les problèmes d'état du système, setWidgetPreview est une API à débit limité. La limite par défaut est d'environ deux appels par heure.

Le système ne fournit pas de rappel pour les aperçus. Votre application doit donc décider quand appeler setWidgetPreviews. La stratégie de mise à jour dépend du cas d'utilisation de votre widget :

  • Si le widget contient des informations statiques ou s'il s'agit d'une action rapide, définissez l'aperçu lors du premier lancement de l'application.
  • Vous pouvez définir l'aperçu une fois que votre application dispose de données, par exemple après la connexion d'un utilisateur ou la configuration initiale.
  • Vous pouvez configurer une tâche périodique pour mettre à jour les aperçus à la fréquence de votre choix.

L'exemple suivant charge une ressource de mise en page de widget XML et la définit comme aperçu. Un paramètre de compilation compileSdk de 35 ou plus est requis pour que setWidgetPreview s'affiche en tant que méthode dans cet extrait.

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

Ajouter des aperçus de widgets redimensionnables

À partir d'Android 12, l'aperçu du widget affiché dans le sélecteur de widgets est redimensionnable. Vous le fournissez sous la forme d'un ensemble de mises en page XML à la taille par défaut du widget. Auparavant, l'aperçu du widget était une ressource drawable statique, ce qui, dans certains cas, entraînait des aperçus qui ne reflétaient pas précisément l'apparence des widgets lorsqu'ils étaient ajoutés à l'écran d'accueil.

Pour implémenter des aperçus de widgets évolutifs, utilisez l'attribut previewLayout de l'élément appwidget-provider pour fournir une mise en page XML :

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

Nous vous recommandons d'utiliser la même mise en page que le widget réel, avec des valeurs par défaut ou de test réalistes. La plupart des applications utilisent les mêmes previewLayout et initialLayout. Pour savoir comment créer des mises en page d'aperçu précises, consultez Créer des aperçus précis incluant des éléments dynamiques.

Nous vous recommandons de spécifier les attributs previewLayout et previewImage afin que votre application puisse utiliser previewImage si l'appareil de l'utilisateur n'est pas compatible avec previewLayout. L'attribut previewLayout est prioritaire sur l'attribut previewImage.

Ajouter des aperçus de widgets statiques pour assurer la rétrocompatibilité

Pour permettre aux sélecteurs de widgets sur Android 11 (niveau d'API 30) ou version antérieure d'afficher des aperçus de votre widget, ou comme solution de secours pour les aperçus évolutifs, spécifiez l'attribut previewImage.

Si vous modifiez l'apparence du widget, mettez à jour l'image d'aperçu.

Cet attribut est également utilisé comme solution de secours pour les aperçus générés si vous n'en avez pas défini un à l'aide de setWidgetPreview.

Créez des aperçus précis incluant des éléments dynamiques.

Figure 1  : Aperçu d'un widget n'affichant aucun élément de liste.

Cette section explique l'approche recommandée pour afficher plusieurs éléments dans l'aperçu d'un widget avec une vue de collection, c'est-à-dire un widget qui utilise un ListView, un GridView ou un StackView. Cela s'applique aux aperçus de widgets évolutifs, et non aux aperçus générés.

Si votre widget utilise l'une de ces vues, la création d'un aperçu évolutif en fournissant la mise en page réelle du widget directement dans previewLayout peut dégrader l'expérience lorsque l'aperçu du widget n'affiche aucun élément. Cela est dû au fait que les données de la vue de collection sont définies de manière dynamique au moment de l'exécution. Elles ressemblent à l'image de la figure 1.

Pour que les aperçus des widgets avec des vues de collection s'affichent correctement dans le sélecteur de widgets, nous vous recommandons de conserver un fichier de mise en page distinct réservé à l'aperçu. Ce fichier de mise en page distinct doit inclure les éléments suivants :

  • La mise en page réelle du widget.
  • Vue de collection d'espaces réservés avec des éléments fictifs. Par exemple, vous pouvez imiter un ListView en fournissant un espace réservé LinearLayout avec plusieurs éléments de liste fictifs.

Pour illustrer un exemple de ListView, commencez par un fichier de mise en page distinct :

// 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>

Spécifiez le fichier de mise en page de l'aperçu lorsque vous fournissez l'attribut previewLayout des métadonnées AppWidgetProviderInfo. Vous devez toujours spécifier la mise en page réelle du widget pour l'attribut initialLayout et utiliser la mise en page réelle du widget lors de la construction d'un RemoteViews au moment de l'exécution.

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

Éléments de liste complexes

L'exemple de la section précédente fournit de faux éléments de liste, car les éléments de liste sont des objets TextView. Il peut être plus complexe de fournir des éléments fictifs si les éléments sont des mises en page complexes.

Prenons l'exemple d'un élément de liste défini dans widget_list_item.xml et composé de deux objets 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>

Pour fournir des éléments de liste fictifs, vous pouvez inclure la mise en page plusieurs fois, mais chaque élément de liste sera alors identique. Pour fournir des éléments de liste uniques, procédez comme suit :

  1. Créez un ensemble d'attributs pour les valeurs de texte :

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. Utilisez ces attributs pour définir le texte :

    <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. Créez autant de styles que nécessaire pour l'aperçu. Redéfinissez les valeurs de chaque style :

    <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. Appliquez les styles aux éléments fictifs dans la mise en page de l'aperçu :

    <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>