Agrega vistas previas al selector de widgets

Para mejorar la experiencia del selector de widgets de tu app, proporciona una vista previa del widget generada en dispositivos con Android 15 y versiones posteriores, una vista previa del widget ajustada (especificando un previewLayout) para dispositivos con Android 12 a Android 14 y un previewImage para versiones anteriores.

Las vistas previas de widgets generadas te permiten crear vistas previas dinámicas y personalizadas para tus widgets que reflejen con precisión cómo aparecerán en la pantalla principal de un usuario. En Android 15 y versiones posteriores, se proporcionan a través de una API de envío, lo que significa que tu app proporciona la vista previa en cualquier momento de su ciclo de vida sin recibir una solicitud explícita del host del widget.

Para obtener más información, consulta Enriquece tu app con novedades en tiempo real y widgets en YouTube.

Agrega vistas previas generadas

Para mostrar vistas previas de widgets generadas en dispositivos con Android 15 o versiones posteriores, primero establece el valor de compileSdk en 35 o una versión posterior en el archivo build.gradle del módulo para poder proporcionar RemoteViews al selector de widgets.

Las apps pueden usar setWidgetPreview en AppWidgetManager. Para evitar el abuso y mitigar los problemas de estado del sistema, setWidgetPreview es una API con límite de frecuencia. El límite predeterminado es de aproximadamente dos llamadas por hora.

No hay una devolución de llamada del sistema para proporcionar vistas previas, por lo que tu app debe decidir cuándo llamar a setWidgetPreviews. La estrategia de actualización depende del caso de uso de tu widget:

  • Si el widget tiene información estática o es una acción rápida, configura la vista previa cuando se inicie la app por primera vez.
  • Puedes configurar la vista previa una vez que tu app tenga datos, por ejemplo, después de que un usuario acceda o realice la configuración inicial.
  • Puedes configurar una tarea periódica para actualizar las vistas previas con la frecuencia que elijas.

En el siguiente ejemplo, se carga un recurso de diseño de widget XML y se establece como la vista previa. Se requiere un parámetro de configuración de compilación compileSdk de 35 o posterior para que setWidgetPreview se muestre como un método en este fragmento.

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

Agrega vistas previas de widgets escalables

A partir de Android 12, la vista previa del widget que se muestra en el selector de widgets es escalable. Debes proporcionarlo como un diseño XML establecido en el tamaño predeterminado del widget. Anteriormente, la vista previa del widget era un recurso de elementos de diseño estático, lo que, en algunos casos, generaba vistas previas que no reflejaban con precisión cómo se veían los widgets cuando se agregaban a la pantalla principal.

Para implementar vistas previas de widgets escalables, usa el atributo previewLayout del elemento appwidget-provider para proporcionar un diseño XML en su lugar:

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

Te recomendamos que uses el mismo diseño que el widget real, con valores predeterminados o de prueba realistas. La mayoría de las apps usan el mismo previewLayout y initialLayout. Para obtener orientación sobre cómo crear diseños de vista previa precisos, consulta Cómo crear vistas previas precisas que incluyan elementos dinámicos.

Te recomendamos que especifiques los atributos previewLayout y previewImage para que tu app pueda recurrir al uso de previewImage si el dispositivo del usuario no admite previewLayout. El atributo previewLayout tiene prioridad sobre el atributo previewImage.

Agrega vistas previas de widgets estáticos para la retrocompatibilidad

Para permitir que los selectores de widgets en Android 11 (nivel de API 30) o versiones anteriores muestren vistas previas de tu widget, o como resguardo para las vistas previas escalables, especifica el atributo previewImage.

Si cambias la apariencia del widget, actualiza la imagen de vista previa.

Este atributo también se usa como resguardo para las vistas previas generadas si no estableciste una con setWidgetPreview.

Compila vistas previas precisas que incluyan elementos dinámicos

Figura 1: Vista previa de un widget que no muestra elementos de lista.

En esta sección, se explica el enfoque recomendado para mostrar varios elementos en una vista previa de un widget con una vista de colección, es decir, un widget que usa un ListView, GridView o StackView. Esto se aplica a las vistas previas de widgets escalables, no a las vistas previas generadas.

Si tu widget usa una de estas vistas, crear una vista previa escalable proporcionando el diseño real del widget directamente en previewLayout puede degradar la experiencia cuando la vista previa del widget no muestra elementos. Esto ocurre porque los datos de la vista de colección se configuran de forma dinámica durante el tiempo de ejecución y se ven de manera similar a la imagen que se muestra en la figura 1.

Para que las vistas previas de los widgets con vistas de colección se muestren correctamente en el selector de widgets, te recomendamos que mantengas un archivo de diseño independiente designado solo para la vista previa. Este archivo de diseño independiente debe incluir lo siguiente:

  • Es el diseño real del widget.
  • Es una vista de colección de marcador de posición con elementos falsos. Por ejemplo, puedes imitar un ListView proporcionando un marcador de posición LinearLayout con varios elementos de lista falsos.

Para ilustrar un ejemplo de un ListView, comienza con un archivo de diseño independiente:

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

Especifica el archivo de diseño de vista previa cuando proporciones el atributo previewLayout de los metadatos AppWidgetProviderInfo. Aún debes especificar el diseño real del widget para el atributo initialLayout y usarlo cuando construyas un RemoteViews en el entorno de ejecución.

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

Elementos de lista complejos

En el ejemplo de la sección anterior, se proporcionan elementos de lista falsos, ya que los elementos de la lista son objetos TextView. Puede ser más complejo proporcionar elementos falsos si estos son diseños complejos.

Considera un elemento de lista que se define en widget_list_item.xml y consta de dos objetos 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>

Para proporcionar elementos de lista falsos, puedes incluir el diseño varias veces, pero esto hace que cada elemento de lista sea idéntico. Para proporcionar elementos de lista únicos, sigue estos pasos:

  1. Crea un conjunto de atributos para los valores de texto:

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. Usa estos atributos para establecer el texto:

    <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 tantos estilos como sea necesario para la vista previa. Redefine los valores en cada estilo:

    <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. Aplica los estilos a los elementos falsos en el diseño de vista previa:

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