Aggiungere anteprime al selettore di widget

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

Le anteprime dei widget generati ti consentono di creare anteprime dinamiche e personalizzate per i tuoi widget che riflettono con precisione il modo in cui appariranno nella schermata Home di un utente. Per Android 15 e versioni successive, vengono forniti tramite un'API push, il che significa che la tua 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 live e widget su YouTube.

Aggiungere le anteprime generate

Per mostrare le anteprime dei widget generati su un dispositivo Android 15 o versioni successive, imposta prima il valore di compileSdk su 35 o versioni successive nel file del modulo build.gradle per avere la possibilità di fornire RemoteViews al selettore di widget

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

Non è previsto un callback dal sistema per fornire anteprime, quindi la tua 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 ha dati, ad esempio dopo l'accesso di un utente o la configurazione iniziale.
  • Puoi configurare un'attività periodica per aggiornare le anteprime alla cadenza che preferisci.

L'esempio seguente carica una risorsa di layout del widget XML e la imposta come anteprima. Per visualizzare setWidgetPreview come metodo in questo snippet, è necessaria un'impostazione di compilazione compileSdk pari a 35 o versioni successive.

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

Aggiungere anteprime dei widget scalabili

A partire da Android 12, l'anteprima del widget visualizzata nel selettore dei widget è scalabile. Lo fornisci come layout XML impostato sulle dimensioni predefinite del widget. In precedenza, l'anteprima del widget era una risorsa disegnabile statica, in alcuni casi portando ad anteprime che riflettevano in modo impreciso l'aspetto dei widget quando vengono aggiunti alla schermata Home.

Per implementare anteprime dei widget scalabili, utilizza l'attributo previewLayout dell'elemento appwidget-provider per fornire invece 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 previewLayout e initialLayout. Per indicazioni sulla creazione di layout di anteprima accurati, consulta Creare anteprime accurate che includano elementi dinamici.

Ti consigliamo di specificare sia gli attributi previewLayout sia 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.

Aggiungere anteprime dei widget statici 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 fallback 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 fallback per le anteprime generate se non ne hai impostata una utilizzando setWidgetPreview.

Creare anteprime accurate che includano elementi dinamici

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

Questa sezione illustra l'approccio consigliato per visualizzare più elementi in un'anteprima del widget per un widget con una visualizzazione raccolta, ovvero un widget che utilizza ListView, GridView o StackView. Ciò 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. Ciò si verifica perché i dati della visualizzazione raccolta vengono impostati dinamicamente in fase di runtime e sono simili all' immagine mostrata nella Figura 1.

Per visualizzare correttamente le anteprime dei widget con visualizzazioni di raccolta 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 della raccolta segnaposto con elementi fittizi. Ad esempio, puoi imitare un ListView fornendo un segnaposto LinearLayout con diversi elementi di elenco fittizi.

Per illustrare un esempio per un 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. Continui a specificare il layout effettivo del widget per l'attributo initialLayout e a utilizzare il layout effettivo del widget quando costruisci 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 voci di elenco fittizie, perché le voci di elenco sono oggetti TextView. Può essere più complesso fornire elementi falsi se gli elementi sono layout complessi.

Considera una voce di elenco definita in widget_list_item.xml e composta 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 voci di elenco fittizie, puoi includere il layout più volte, ma in questo modo ogni voce di elenco sarà identica. Per fornire elementi di elenco unici, 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>