为了改进应用的微件选择器体验,请在搭载 Android 15 及更高版本的设备上提供生成的微件预览,在搭载 Android 12 至 Android 14 的设备上提供缩放的微件预览(通过指定 previewLayout),并在更早的版本中提供 previewImage。
借助生成的 widget 预览,您可以为 widget 创建动态的个性化预览,准确反映它们在用户主屏幕上的显示方式。对于 Android 15 及更高版本,它们通过推送 API 提供,这意味着您的应用可以在其生命周期的任何时间点提供预览,而无需接收来自 widget 主机的明确请求。
如需了解详情,请观看 YouTube 上的利用实时更新和 widget 丰富您的应用视频。
添加生成的预览
如需在 Android 15 或更高版本的设备上显示生成的微件预览,请先在模块 build.gradle 文件中将 compileSdk 值设置为 35 或更高值,以便能够向微件选择器提供 RemoteViews
应用可以在 AppWidgetManager 中使用 setWidgetPreview。为防止滥用并缓解系统健康问题,setWidgetPreview 是一个受速率限制的 API。默认限制为每小时大约两次。
系统没有提供预览的回调,因此您的应用必须决定何时调用 setWidgetPreviews。更新策略取决于微件的使用场景:
- 如果 widget 包含静态信息或属于快速操作,请在应用首次启动时设置预览。
- 您可以在应用拥有数据后(例如,在用户登录或完成初始设置后)设置预览。
- 您可以设置定期任务,以按所选频率更新预览。
以下示例加载 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)
)
添加可缩放的 widget 预览
从 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 属性。
如果您更改了微件的外观,请更新预览图片。
如果您未使用 setWidgetPreview 设置预览,此属性还会用作生成的预览的后备。
构建包含动态商品的准确预览
本部分介绍了在具有集合视图的微件(即使用 ListView、GridView 或 StackView 的微件)的微件预览中显示多个项的推荐方法。这适用于可缩放 widget 预览,而不适用于生成的预览。
如果您的 widget 使用了上述某个视图,那么直接在 previewLayout 中提供实际的 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_preview"
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>