Aggiungere anteprime al selettore di widget

Per migliorare l'esperienza del selettore di widget della tua app, fornisci un'anteprima del widget generata sui dispositivi Android 15 e versioni successive, un'anteprima del widget scalata (specificando un previewLayout) per i dispositivi Android 12-Android 14 e un previewImage per le versioni precedenti.

Le anteprime dei widget generate ti consentono di creare anteprime dinamiche e personalizzate per i tuoi widget che riflettono con precisione l'aspetto che avranno nella schermata Home di un utente. Per Android 15 e versioni successive, vengono fornite tramite un'API push, il che significa che l'app fornisce l'anteprima in qualsiasi momento del suo ciclo di vita senza ricevere una richiesta esplicita dall'host del widget.

Per saperne di più, guarda il video Arricchisci la tua app con aggiornamenti in tempo reale e widget su YouTube.

Aggiungi anteprime generate

Per mostrare le anteprime dei widget generate su un dispositivo Android 15 o versioni successive, imposta innanzitutto il valore compileSdk su 35 o versioni successive nel file del modulo build.gradle per poter fornire RemoteViews al selettore di widget

Le app possono utilizzare setWidgetPreview in AppWidgetManager. Per prevenire usi impropri e mitigare i problemi di integrità del sistema, setWidgetPreview è un'API con limitazione di frequenza. Il limite predefinito è di circa due chiamate all'ora.

Non esiste un callback dal sistema per fornire le anteprime, quindi l'app deve decidere quando chiamare setWidgetPreviews. La strategia di aggiornamento dipende dal caso d'uso del widget:

  • Se il widget contiene informazioni statiche o è un'azione rapida, imposta l'anteprima al primo avvio dell'app.
  • Puoi impostare l'anteprima una volta che l'app contiene dati, ad esempio dopo l'accesso di un utente o la configurazione iniziale.
  • Puoi configurare un'attività periodica per aggiornare le anteprime con una cadenza scelta.

L'esempio seguente carica una risorsa di layout del widget XML e la imposta come anteprima. Perché setWidgetPreview venga visualizzato come metodo in questo snippet, è necessaria un'impostazione di build compileSdk pari o superiore a 35.

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

Aggiungi anteprime dei widget scalabili

A partire da Android 12, l'anteprima del widget visualizzata nel selettore dei widget è scalabile. Devi fornirla come layout XML impostato sulle dimensioni predefinite del widget. In precedenza, l'anteprima del widget era una risorsa drawable statica, il che in alcuni casi comportava anteprime che non riflettevano con precisione l'aspetto dei widget quando venivano aggiunti alla schermata Home.

Per implementare anteprime dei widget scalabili, utilizza l'attributo previewLayout dell'elemento appwidget-provider per fornire un layout XML:

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

Ti consigliamo di utilizzare lo stesso layout del widget effettivo, con valori predefiniti o di test realistici. La maggior parte delle app utilizza gli stessi valori per previewLayout e initialLayout. Per indicazioni sulla creazione di layout di anteprima accurati, consulta Crea anteprime accurate che includono elementi dinamici.

Ti consigliamo di specificare entrambi gli attributi previewLayout e previewImage, in modo che la tua app possa utilizzare previewImage se il dispositivo dell'utente non supporta previewLayout. L'attributo previewLayout ha la precedenza sull'attributo previewImage.

Aggiungi anteprime statiche dei widget per la compatibilità con le versioni precedenti

Per consentire ai selettori di widget su Android 11 (livello API 30) o versioni precedenti di mostrare le anteprime del tuo widget o come opzione di riserva per le anteprime scalabili, specifica l'attributo previewImage.

Se modifichi l'aspetto del widget, aggiorna l'immagine di anteprima.

Questo attributo viene utilizzato anche come riserva per le anteprime generate se non ne hai impostata una utilizzando setWidgetPreview.

Crea anteprime accurate che includono elementi dinamici

Figura 1: un'anteprima del widget che non mostra elementi dell'elenco.

Questa sezione spiega l'approccio consigliato per visualizzare più elementi nell'anteprima di un widget con una vista raccolta, ovvero un widget che utilizza un ListView, un GridView o un StackView. Questo vale per le anteprime dei widget scalabili, non per le anteprime generate.

Se il widget utilizza una di queste visualizzazioni, la creazione di un'anteprima scalabile fornendo il layout effettivo del widget direttamente in previewLayout può peggiorare l'esperienza quando l'anteprima del widget non mostra elementi. Questo accade perché i dati della visualizzazione della raccolta vengono impostati in modo dinamico in fase di runtime e l'aspetto è simile all'immagine mostrata nella Figura 1.

Per fare in modo che le anteprime dei widget con visualizzazioni di raccolte vengano visualizzate correttamente nel selettore di widget, ti consigliamo di mantenere un file di layout separato designato solo per l'anteprima. Questo file di layout separato deve includere quanto segue:

  • Il layout effettivo del widget.
  • Una visualizzazione di raccolta segnaposto con elementi fittizi. Ad esempio, puoi simulare un ListView fornendo un segnaposto LinearLayout con diversi elementi di elenco fittizi.

Per illustrare un esempio di ListView, inizia con un file di layout separato:

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

Specifica il file di layout dell'anteprima quando fornisci l'attributo previewLayout dei metadati AppWidgetProviderInfo. Devi comunque specificare il layout effettivo del widget per l'attributo initialLayout e utilizzare il layout effettivo del widget durante la creazione di un RemoteViews in fase di runtime.

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

Voci di elenco complesse

L'esempio nella sezione precedente fornisce elementi dell'elenco fittizi, perché gli elementi dell'elenco sono oggetti TextView. Può essere più complesso fornire elementi fittizi se questi hanno layout complessi.

Considera un elemento di un elenco definito in widget_list_item.xml e composto da due oggetti 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>

Per fornire elementi dell'elenco fittizi, puoi includere il layout più volte, ma in questo modo ogni elemento dell'elenco sarà identico. Per fornire elementi dell'elenco univoci, segui questi passaggi:

  1. Crea un insieme di attributi per i valori di testo:

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. Utilizza questi attributi per impostare il testo:

    <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. Crea tutti gli stili necessari per l'anteprima. Ridefinisci i valori in ogni stile:

    <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. Applica gli stili agli elementi fittizi nel layout di anteprima:

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