本页面介绍了关于微件大小调整和更高灵活性的优化措施 在 Android 12(API 级别 31)中引入。还详细介绍了 确定 widget 的大小。
使用改进的 API 设置微件大小和布局
从 Android 12(API 级别 31)开始,您可以提供更精细的尺寸 属性和灵活布局,具体如 以下部分:
在以前的 Android 版本中,可以获取
使用
OPTION_APPWIDGET_MIN_WIDTH
、
OPTION_APPWIDGET_MIN_HEIGHT
,
OPTION_APPWIDGET_MAX_WIDTH
,
和OPTION_APPWIDGET_MAX_HEIGHT
extra,然后估算 widget 的大小,但该逻辑并非适用于所有模式
情况。对于以 Android 12 或更高版本为目标平台的微件,我们建议
提供自适应或完全匹配
布局。
指定额外的微件大小调整限制
Android 12 新增了一些 API,可让您确保微件 在具有不同屏幕尺寸的不同设备上更可靠地调整尺寸。
除了现有的 minWidth
、minHeight
、minResizeWidth
和 minResizeHeight
属性之外,还可以使用下面这些新的 appwidget-provider
属性:
targetCellWidth
和targetCellHeight
: 根据启动器网格单元格定义 widget 的目标大小。定义后,会使用这些属性,而不是minWidth
或minHeight
。maxResizeWidth
和maxResizeHeight
: 定义启动器允许用户将微件调整到的最大尺寸。
以下 XML 展示了如何使用大小调整属性。
<appwidget-provider
...
android:targetCellWidth="3"
android:targetCellHeight="2"
android:maxResizeWidth="250dp"
android:maxResizeHeight="110dp">
</appwidget-provider>
提供自适应布局
如果布局需要根据微件的大小进行更改,我们建议您创建一小组布局,每个布局对一定范围的大小有效。如果 另一种方法,就是根据精确的微件提供布局 运行时大小,如本页所述。
此功能可实现更顺畅的扩缩,并提升整体的系统性能 运行状况,因为系统不必每次都唤醒应用 它会以不同的尺寸显示该 widget。
以下代码示例展示了如何提供布局列表。
Kotlin
override fun onUpdate(...) { val smallView = ... val tallView = ... val wideView = ... 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) }
Java
@Override public void onUpdate(...) { RemoteViews smallView = ...; RemoteViews tallView = ...; RemoteViews wideView = ...; Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>(); viewMapping.put(new SizeF(150f, 100f), smallView); viewMapping.put(new SizeF(150f, 200f), tallView); viewMapping.put(new SizeF(215f, 100f), wideView); RemoteViews remoteViews = new RemoteViews(viewMapping); appWidgetManager.updateAppWidget(id, remoteViews); }
假设该 widget 具有以下属性:
<appwidget-provider
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
。在这个范围内
您可以决定布局切换的临界点。
![自适应布局示例](https://developer.android.google.cn/static/images/appwidgets/size-range.gif?authuser=9&hl=hu)
提供精确布局
如果一小组自适应布局不可行,您可以改为提供根据微件的显示大小量身定制的不同布局。通常,手机有两种大小(竖屏和横屏模式),可折叠设备有四种大小。
如需实现此解决方案,您的应用需要执行以下步骤:
过载
AppWidgetProvider.onAppWidgetOptionsChanged()
,当一组大小发生更改时,就会调用此方法。调用
AppWidgetManager.getAppWidgetOptions()
,这样会返回包含大小的Bundle
。访问
Bundle
中的AppWidgetManager.OPTION_APPWIDGET_SIZES
键。
以下代码示例展示了如何提供精确布局。
Kotlin
override fun onAppWidgetOptionsChanged( context: Context, appWidgetManager: AppWidgetManager, id: Int, newOptions: Bundle? ) { super.onAppWidgetOptionsChanged(context, appWidgetManager, id, newOptions) // Get the new sizes. val sizes = newOptions?.getParcelableArrayList<SizeF>( AppWidgetManager.OPTION_APPWIDGET_SIZES ) // 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 { }
Java
@Override public void onAppWidgetOptionsChanged( Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); // Get the new sizes. ArrayList<SizeF> sizes = newOptions.getParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES); // Check that the list of sizes is provided by the launcher. if (sizes == null || sizes.isEmpty()) { return; } // Map the sizes to the RemoteViews that you want. Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>(); for (SizeF size : sizes) { viewMapping.put(size, createRemoteViews(size)); } RemoteViews remoteViews = new RemoteViews(viewMapping); appWidgetManager.updateAppWidget(id, remoteViews); } // Create the RemoteViews for the given size. private RemoteViews createRemoteViews(SizeF size) { }
确定 widget 的大小
每个 widget 都必须为设备定义 targetCellWidth
和 targetCellHeight
搭载 Android 12 或更高版本,或者对于所有搭载 Android 12 或更高版本的用户,使用 minWidth
和 minHeight
Android 版本 - 指示占用的最小空间量
默认情况。不过,当用户向主屏幕添加微件时,通常
占用的宽度和高度大于您指定的最小宽度和高度。
Android 主屏幕为用户提供了可用空间网格,供他们在其中
放置微件和图标。此网格可能会因设备而异;例如,许多
手机采用 5x4 网格,平板电脑则提供更大的网格。当微件
被拉伸以占据最小数量的单元格
水平和垂直方向上,需要满足其
targetCellWidth
和targetCellHeight
(在运行的设备上)
Android 12 或更高版本,或者 minWidth
和 minHeight
限制条件
搭载 Android 11(API 级别 30)或更低版本的设备。
单元格的宽度和高度以及自动应用外边距的大小 也会因设备而异使用下表大致估算出 在典型的 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 米 | (73 米 - 16)x(118 米 - 16) | (142 米 - 15)x(66 米 - 15) |
使用纵向模式的单元格大小来说明您提供的值
minWidth
、minResizeWidth
和 maxResizeWidth
属性。同样,
使用横屏模式的单元格大小来决定您提供的值
minHeight
、minResizeHeight
和 maxResizeHeight
属性。
原因在于,在纵向模式下,单元格的宽度通常较小 与横向模式相比,采用横向模式时,单元格高度通常为 相较于纵向模式,尺寸小
例如,如果您希望将微件的宽度调整到
如果是 Google Pixel 4,则需要将 minResizeWidth
设置为不超过 56dp
以确保 minResizeWidth
属性的值较小
大于 57dp,因为纵向模式下单元格的宽度至少为 57dp。
同样,如果您希望微件高度可在
您需要将 minResizeHeight
设置为不超过 50dp,以确保
minResizeHeight
属性的值小于
51dp - 因为一个单元格在横屏模式下的高度至少为 51dp。
每个 widget 均可在
minResizeWidth
/minResizeHeight
和 maxResizeWidth
/maxResizeHeight
属性,这意味着它需要适应这些对象之间的任何尺寸范围。
例如,要在展示位置上设置微件的默认尺寸,您可以 设置以下属性:
<appwidget-provider
android:targetCellWidth="3"
android:targetCellHeight="2"
android:minWidth="180dp"
android:minHeight="110dp">
</appwidget-provider>
这意味着该微件的默认大小为 3x2 单元格,
targetCellWidth
和 targetCellHeight
属性,即 180×110dp,例如
由 minWidth
和 minHeight
指定(针对运行
Android 11 或更低版本。在后一种情况下,单元格中的大小
因设备而异。
此外,如需设置微件支持的尺寸范围,您可以设置以下 属性:
<appwidget-provider
android:minResizeWidth="180dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="530dp"
android:maxResizeHeight="450dp">
</appwidget-provider>
正如以上属性所指定,微件的宽度为 大小可调整为 180dp 至 530dp,高度可调整为 110dp 至 450dp。 然后,可以调整该微件的大小,使其介于 3x2 到 5x2 的单元格之间,但需满足以下条件: 条件:
- 设备采用 5x4 网格。
- 单元格数量和可用大小(以 dp 为单位)之间的映射 遵循显示最低价格估算值的表格 维度。
- 该 widget 会适应该尺寸范围。
Kotlin
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))
Java
RemoteViews smallView = new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_small); RemoteViews mediumView = new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_medium); RemoteViews largeView = new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_large); Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>(); viewMapping.put(new SizeF(180f, 110f), smallView); viewMapping.put(new SizeF(270f, 110f), mediumView); viewMapping.put(new SizeF(270f, 280f), largeView); RemoteViews remoteViews = new RemoteViews(viewMapping); appWidgetManager.updateAppWidget(id, remoteViews);
假设该 widget 使用前面定义的响应式布局
代码段。也就是说,
使用 R.layout.widget_weather_forecast_small
时,最低为 180dp (minResizeWidth
) x
110dp (minResizeHeight
) 到 269x279dp(下一个临界点 - 1)。同样,
R.layout.widget_weather_forecast_medium
的使用范围为 270x110dp 到 270x279dp,
以及从 270x280dp 到 R.layout.widget_weather_forecast_large
530dp (maxResizeWidth
) x 450dp (maxResizeHeight
)。
当用户调整微件的大小时,其外观会随之改变以适应 单元格,如以下示例所示。
![最小 3x2 网格大小的天气 widget 示例。界面会显示
位置名称(东京)、温度 (14°) 以及指示符
局部多云天气。](https://developer.android.google.cn/static/images/appwidgets/weather-size-3x2.png?authuser=9&hl=hu)
R.layout.widget_weather_forecast_small
。![4x2“medium”中的天气 widget 示例。调整 widget 大小
这种方法基于之前的 widget 大小的所有界面构建,
并添加了“以多云为主”标签以及从
下午 4 点至晚上 7 点。](https://developer.android.google.cn/static/images/appwidgets/weather-size-4x2.png?authuser=9&hl=hu)
R.layout.widget_weather_forecast_medium
。![5x2“medium”中的天气 widget 示例。调整 widget 大小
这样生成的界面与之前的尺寸相同
将单元格拉伸一个单元格,以占据更多水平空间。](https://developer.android.google.cn/static/images/appwidgets/weather-size-5x2.png?authuser=9&hl=hu)
R.layout.widget_weather_forecast_medium
。![5x3“大”尺寸的天气 widget 示例。调整 widget 大小
这种方法基于之前微件大小的所有界面构建,
并在该 widget 内添加一个包含天气预报的视图
。表示晴天或雨天的符号
以及每日最高和最低温度](https://developer.android.google.cn/static/images/appwidgets/weather-size-5x3.png?authuser=9&hl=hu)
R.layout.widget_weather_forecast_large
。![5x4“大”尺寸的天气 widget 示例。调整 widget 大小
这种方法基于之前微件大小的所有界面构建,
并添加星期四和星期五(以及相应的符号
用于表示天气类型以及最高温度和最低温度
)。](https://developer.android.google.cn/static/images/appwidgets/weather-size-5x4.png?authuser=9&hl=hu)
R.layout.widget_weather_forecast_large
。