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