借助生成的 widget 预览,您可以为 widget 创建动态的个性化预览,准确反映它们在用户主屏幕上的显示方式。它们通过推送 API 提供,这意味着您的应用可以在其生命周期的任何时间点提供预览,而无需接收来自 widget 主机的明确请求。
为了改进应用的 widget 选择器体验,请在搭载 Android 15 及更高版本的设备上提供生成的 widget 预览,在搭载 Android 12 至 Android 14 的设备上提供缩放的 widget 预览(通过指定 previewLayout
),并在更早的版本中提供 previewImage
。
如需了解详情,请观看 YouTube 上的利用实时更新和 widget 丰富您的应用视频。
设置应用以进行生成的 widget 预览
如需在 Android 15 或更高版本的设备上显示生成的微件预览,请先在模块 build.gradle
文件中将 compileSdk
值设置为 35 或更高值,以便能够向微件选择器提供 RemoteViews
然后,应用可以在 GlanceAppWidgetManager
或 AppWidgetManager
中使用 setWidgetPreview
。为防止滥用并缓解系统健康问题,setWidgetPreview
是一个受速率限制的 API。默认限制为每小时大约两次调用。
使用 Jetpack Glance 生成更新后的预览
对于使用 Jetpack Glance 构建的 widget,请执行以下操作:
替换
GlanceAppWidget.providePreview
函数以提供预览的可组合内容。与在provideGlance
中一样,加载应用的数据并将其传递给 widget 的内容可组合项,以确保预览显示准确的数据。与provideGlance
不同,这是一个没有重组或效果的单一组合。调用
GlanceAppWidgetManager.setWidgetPreviews
以生成并发布预览。
系统没有提供预览的回调,因此您的应用必须决定何时调用 setWidgetPreviews
。更新策略取决于微件的使用场景:
- 如果 widget 包含静态信息或属于快速操作,请在应用首次启动时设置预览。
- 您可以在应用拥有数据后(例如,在用户登录或完成初始设置后)设置预览。
- 您可以设置定期任务,以按所选频率更新预览。
排查生成的预览方面的问题
一个常见问题是,在生成预览后,相对于 widget 的放置大小,预览图片中可能会缺少图片、图标或其他可组合项。此放置大小由 targetCellWidth
和 targetCellHeight
(如果已指定)或应用 widget 提供程序信息文件中的 minWidth
和 minHeight
定义。
这是因为 Android 默认情况下仅渲染在 widget 的最小尺寸下可见的可组合项。换句话说,Android 默认将 previewSizeMode
设置为 SizeMode.Single
。它使用应用 widget 提供程序信息 XML 中的 android:minHeight
和 android:minWidth
来确定要绘制哪些可组合项。
如需解决此问题,请在 GlanceAppWidget
中替换 previewSizeMode
并将其设置为 SizeMode.Responsive
,从而提供一组 DpSize
值。这会告知 Android 需要渲染的所有布局尺寸以进行预览,从而确保所有元素都能正确显示。
针对特定外形规格进行优化。提供 1 或 2 个尺寸,从最小值开始,并遵循 widget 的断点。指定至少一张用于向后兼容的图片。您可以在微件设计指南中找到不同网格尺寸对应的适当最小 DP 值。
生成不含 Jetpack Glance 的更新预览
您可以在不使用 Glance 的情况下使用 RemoteViews
。以下示例加载 XML widget 布局资源并将其设置为预览。如果 setWidgetPreview
要在此代码段中显示为方法,则必须将 compileSdk build 设置设为 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 布局提供,该布局设置为微件的默认大小。以前,微件预览是静态可绘制资源,在某些情况下,会导致预览无法准确反映微件添加到主屏幕后的显示效果。
如需实现可缩放的 widget 预览,请改用 appwidget-provider
元素的 previewLayout
属性来提供 XML 布局:
<appwidget-provider
android:previewLayout="@layout/my_widget_preview">
</appwidget-provider>
我们建议使用与实际 widget 相同的布局,并使用真实的默认值或测试值。大多数应用都使用相同的 previewLayout
和 initialLayout
。如需有关创建准确的预览版布局的指导,请参阅本页中的以下部分。
我们建议您同时指定 previewLayout
和 previewImage
属性,以便在用户设备不支持 previewLayout
时,您的应用可以回退到使用 previewImage
。previewLayout
属性的优先级高于 previewImage
属性。
微件预览的向后兼容性
为使 Android 11(API 级别 30)或更低版本中的微件选择器能够显示微件的预览,或者作为生成的预览的后备方案,请指定 previewImage
属性。
如果您更改了微件的外观,请更新预览图片。
构建包含动态商品的准确预览

本部分介绍了在具有集合视图的微件(即使用 ListView
、GridView
或 StackView
的微件)的微件预览中显示多个项的推荐方法。这不适用于生成的 widget 预览。
如果您的 widget 使用了上述某个视图,那么通过直接提供实际 widget 布局来创建可缩放的预览会在 widget 预览不显示任何项时降低体验。这是因为集合视图数据是在运行时动态设置的,并且看起来与图 1 中显示的图片类似。
为了使包含集合视图的 widget 预览在 widget 选择器中正确显示,我们建议维护一个专门用于预览的单独布局文件。此单独的布局文件应包含以下内容:
- 实际 widget 布局。
- 包含虚假项的占位集合视图。例如,您可以通过提供包含多个虚假列表项的占位符
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
属性指定实际 widget 布局,并在运行时构建 RemoteViews
时使用实际 widget 布局。
<appwidget-provider
previewLayout="@layout/widget_previe"
initialLayout="@layout/widget_view" />
复杂列表项
上一部分中的示例提供了虚假列表项,因为列表项是 TextView
对象。如果项是复杂的布局,则提供虚假项可能会更复杂。
假设在 widget_list_item.xml
中定义了一个列表项,该列表项包含两个 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>
如需提供虚假列表项,您可以多次包含该布局,但这会导致每个列表项都相同。如需提供唯一的列表项,请按以下步骤操作:
为文本值创建一组属性:
<resources> <attr name="widgetTitle" format="string" /> <attr name="widgetContent" format="string" /> </resources>
使用以下属性设置文本:
<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>
根据预览需要创建任意数量的样式。重新定义每种样式中的值:
<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>
在预览布局中对虚假项应用样式:
<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>