本页介绍了 Android 12(API 级别 31)中引入的微件大小调整改进和更大的灵活性。此外,还详细介绍了如何 确定微件的大小。
使用改进的 API 设置微件大小和布局
从 Android 12(API 级别 31)开始,您可以提供更精细的大小属性和灵活的布局,具体方法如下(如后续部分所述):
在之前的 Android 版本中,可以使用
OPTION_APPWIDGET_MIN_WIDTH、
OPTION_APPWIDGET_MIN_HEIGHT、
OPTION_APPWIDGET_MAX_WIDTH和
OPTION_APPWIDGET_MAX_HEIGHT
extra 获取微件的大小范围,然后估计微件的大小,但该逻辑并非在所有
情况下都适用。对于以 Android 12 或更高版本为目标平台的微件,
我们建议您提供 自适应布局 或 精确布局。
指定额外的微件大小调整限制
Android 12 添加了 API,可让您确保微件在不同屏幕尺寸的设备上更可靠地调整大小。
除了现有的 minWidth、
minHeight、
minResizeWidth、
和 minResizeHeight
属性之外,还可以使用下面这些新的 appwidget-provider 属性:
targetCellWidth和targetCellHeight: 根据启动器网格单元定义微件的目标大小。定义后,会使用这些属性,而不是minWidth或minHeight。maxResizeWidth和maxResizeHeight: 定义启动器允许 用户调整微件大小的大小上限。
以下 XML 说明了如何使用调整大小属性。
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:targetCellWidth="3" android:targetCellHeight="2" android:maxResizeWidth="250dp" android:maxResizeHeight="110dp"> </appwidget-provider>
提供自适应布局
如果布局需要根据微件的大小进行更改,我们建议您创建一小组布局,每个布局对一定范围的大小有效。如果无法做到这一点,另一种方法是根据运行时的 精确微件大小来提供布局,如本页所述。
实现此功能可使缩放更流畅并让系统的整体运行状况更好;这是因为,系统不必每次以不同的大小显示微件时都唤醒应用。
以下代码示例展示了如何提供布局列表。
override fun onUpdate( /* ... */ ) { val smallView = RemoteViews( /* ... */ ) val tallView = RemoteViews( /* ... */ ) val wideView = RemoteViews( /* ... */ ) val viewMapping: Map<SizeF, RemoteViews> = mapOf( SizeF(150f, 100f) to smallView, SizeF(150f, 200f) to tallView, SizeF(215f, 100f) to wideView ) val remoteViews = RemoteViews(viewMapping) appWidgetManager.updateAppWidget(id, remoteViews) }
假设微件具有以下属性:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minResizeWidth="160dp" android:minResizeHeight="110dp" android:maxResizeWidth="250dp" android:maxResizeHeight="200dp"> </appwidget-provider>
前面的代码段表示以下内容:
smallView支持从 160dp (minResizeWidth) × 110dp (minResizeHeight) 到 160dp × 199dp(下一个分界点 - 1dp)。tallView支持从 160dp × 200dp 到 214dp(下一个分界点 - 1)× 200dp。wideView支持从 215dp × 110dp (minResizeHeight) 到 250dp (maxResizeWidth) × 200dp (maxResizeHeight)。
您的微件必须支持从 minResizeWidth × minResizeHeight 到 maxResizeWidth × maxResizeHeight 的大小范围。在该范围内,您可以决定切换布局的分界点。
提供精确布局
如果一小组自适应布局不可行,您可以改为提供根据微件的显示大小量身定制的不同布局。通常,手机有两种大小(竖屏和横屏模式),可折叠设备有四种大小。
如需实现此解决方案,您的应用需要执行以下步骤:
过载
AppWidgetProvider.onAppWidgetOptionsChanged(),当一组大小发生更改时,就会调用此方法。调用
AppWidgetManager.getAppWidgetOptions(),这样会返回包含大小的Bundle。访问
Bundle中的AppWidgetManager.OPTION_APPWIDGET_SIZES键。
以下代码示例展示了如何提供精确布局。
override fun onAppWidgetOptionsChanged( context: Context, appWidgetManager: AppWidgetManager, id: Int, newOptions: Bundle? ) { super.onAppWidgetOptionsChanged(context, appWidgetManager, id, newOptions) // Get the new sizes. val sizes = newOptions?.let { BundleCompat.getParcelableArrayList( it, AppWidgetManager.OPTION_APPWIDGET_SIZES, SizeF::class.java ) } // Check that the list of sizes is provided by the launcher. if (sizes.isNullOrEmpty()) { return } // Map the sizes to the RemoteViews that you want. val remoteViews = RemoteViews(sizes.associateWith(::createRemoteViews)) appWidgetManager.updateAppWidget(id, remoteViews) } // Create the RemoteViews for the given size. private fun createRemoteViews(size: SizeF): RemoteViews { }
确定微件的大小
每个微件都必须为搭载 Android 12 或更高版本的设备定义 targetCellWidth 和 targetCellHeight,或者为所有 Android 版本定义 minWidth 和 minHeight,以指明其默认占用的最小空间量。不过,当用户向其主屏幕添加微件时,微件占用的宽度和高度通常会超过您指定的最小值。
Android 主屏幕为用户提供了一个可用空间网格,供他们放置微件和图标。此网格可能因设备而异;例如,许多手机提供 5x4 网格,而平板电脑可以提供更大的网格。添加微件后,它会拉伸以占用满足其在搭载 Android 12 或更高版本的设备上的 targetCellWidth 和 targetCellHeight 约束或在搭载 Android 11(API 级别 30)或更低版本的设备上的 minWidth 和 minHeight 约束所需的最小单元格数(横向和纵向)。
单元格尺寸和自动外边距因设备而异。您可以使用下表根据所需占用的网格单元格数,估算微件在典型的 5x4 网格手机上的最小尺寸:
| 单元格数(宽 x 高) | 竖屏模式下的可用大小 (dp) | 横屏模式下的可用大小 (dp) |
|---|---|---|
| 1x1 | 57x102dp | 127x51dp |
| 2x1 | 130x102dp | 269x51dp |
| 3x1 | 203x102dp | 412x51dp |
| 4x1 | 276x102dp | 554x51dp |
| 5x1 | 349x102dp | 697x51dp |
| 5x2 | 349x220dp | 697x117dp |
| 5x3 | 349x337dp | 697x184dp |
| 5x4 | 349x455dp | 697x250dp |
| ... | ... | ... |
| n x m | (73n - 16) x (118m - 16) | (142n - 15) x (66m - 15) |
使用竖屏模式单元格大小来确定您为 minWidth、minResizeWidth 和 maxResizeWidth 属性提供的值。同样,使用横屏模式单元格大小来确定您为 minHeight、minResizeHeight 和 maxResizeHeight 属性提供的值。
原因是,单元格宽度在竖屏模式下通常比在横屏模式下小,同样,单元格高度在横屏模式下通常比在竖屏模式下小。
例如,如果您希望微件宽度在 Google Pixel 4 上可调整为 1 个单元格,则需要将 minResizeWidth 设置为最多 56dp,以确保 minResizeWidth 属性的值小于 57dp,因为单元格在竖屏模式下至少为 57dp 宽。
同样,如果您希望微件高度在同一设备上可调整为 1 个单元格,则需要将 minResizeHeight 设置为最多 50dp,以确保 minResizeHeight 属性的值小于 51dp,因为单元格在横屏模式下至少为 51dp 高。
每个微件都可以在 minResizeWidth/minResizeHeight 和 maxResizeWidth/maxResizeHeight 属性之间的大小范围内调整大小,这意味着它需要适应它们之间的任何大小范围。
例如,如需设置微件在展示位置上的默认大小,您可以设置以下属性:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:targetCellWidth="3" android:targetCellHeight="2" android:minWidth="180dp" android:minHeight="110dp"> </appwidget-provider>
这意味着微件的默认大小为 3x2 个单元格(由 targetCellWidth 和 targetCellHeight 属性指定),或者为 180×110dp(由搭载 Android 11 或更低版本的设备的 minWidth 和 minHeight 指定)。在后一种情况下,单元格大小可能因设备而异。
此外,如需设置微件支持的大小范围,您可以设置以下属性:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minResizeWidth="180dp" android:minResizeHeight="110dp" android:maxResizeWidth="530dp" android:maxResizeHeight="450dp"> </appwidget-provider>
如上述属性所指定,微件的宽度可从 180dp 调整为 530dp,高度可从 110dp 调整为 450dp。 然后,只要满足以下条件,微件就可以从 3x2 个单元格调整为 5x2 个单元格:
- 设备具有 5x4 网格。
- 单元格数与 dp 中的可用大小之间的映射 遵循本页中显示最小尺寸估算 的表格。
- 微件适应该大小范围。
val smallView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_small) val mediumView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_medium) val largeView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_large) val viewMapping: Map<SizeF, RemoteViews> = mapOf( SizeF(180f, 110f) to smallView, SizeF(270f, 110f) to mediumView, SizeF(270f, 280f) to largeView ) appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(viewMapping))
假设微件使用前面代码段中定义的自适应布局。这意味着,指定的布局 R.layout.widget_weather_forecast_small 的大小范围为 180dp (minResizeWidth) x 110dp (minResizeHeight) 到 269x279dp(下一个分界点 - 1)。同样,R.layout.widget_weather_forecast_medium 的大小范围为 270x110dp 到 270x279dp,R.layout.widget_weather_forecast_large 的大小范围为 270x280dp 到 530dp (maxResizeWidth) x 450dp (maxResizeHeight)。
当用户调整微件大小时,其外观会发生变化,以适应每个单元格大小,如以下示例所示。
R.layout.widget_weather_forecast_small。
R.layout.widget_weather_forecast_medium。
R.layout.widget_weather_forecast_medium。
R.layout.widget_weather_forecast_large。
R.layout.widget_weather_forecast_large。