英格兰世界杯预选赛_世界杯卡塔尔 - sctzjx.com

创建 widget 布局

  • Home
  • 世界杯卫冕
  • 创建 widget 布局
  • 2025-08-15 04:45:45
  • admin

尝试使用 Compose 方式

Jetpack Compose 是推荐用于 Android 的界面工具包。了解如何使用 Compose 风格的 API 构建 widget。

Jetpack Glance →

应用微件是可以嵌入其他应用(如主屏幕)并接收定期更新的微型应用视图。这些视图在界面中称为微件,您可以使用应用微件提供程序(或微件提供程序)发布微件。容纳其他 widget 的应用组件称为应用 widget 宿主(或 widget 宿主)。图 1 显示了一个示例音乐 widget:

图 1. 音乐 widget 示例。

本文档介绍了如何使用 widget 提供程序发布 widget。如需详细了解如何创建自己的 AppWidgetHost 来托管应用 widget,请参阅构建 widget 托管应用。

如需了解如何设计微件,请参阅应用微件概览。

微件组件

如需创建 widget,您需要以下基本组件:

AppWidgetProviderInfo 对象

描述 widget 的元数据,例如 widget 的布局、更新频率和 AppWidgetProvider 类。AppWidgetProviderInfo 是在 XML 中定义的,如本文档中所述。

AppWidgetProvider 类

定义允许您以编程方式与 widget 连接的基本方法。通过它,您会在更新、启用、停用或删除 widget 时收到广播。您可以在清单中声明 AppWidgetProvider,然后按照本文档中的说明实现该功能。

视图布局

定义 widget 的初始布局。布局在 XML 中定义,如本文档中所述。

图 2 显示了这些组件如何融入整个应用 widget 处理流程。

图 2. 应用 widget 处理流程。

注意: Android Studio 可以自动创建一组 AppWidgetProviderInfo、AppWidgetProvider 和视图布局文件。依次选择新建 > Widget > 应用 Widget。

如果您的 widget 需要用户配置,请实现应用 widget 配置 activity。此 activity 可让用户修改 widget 设置,例如时钟 widget 的时区。

从 Android 12(API 级别 31)开始,您可以提供默认配置,并允许用户稍后重新配置 widget。如需了解详情,请参阅使用 widget 的默认配置和允许用户重新配置已放置的 widget。

在 Android 11(API 级别 30)或更低版本中,每当用户将 widget 添加到其主屏幕时,系统都会启动此 activity。

我们还建议您进行以下改进:灵活的 widget 布局、各种增强功能、高级 widget、集合 widget 和构建 widget 宿主。

声明 AppWidgetProviderInfo XML

AppWidgetProviderInfo 对象定义了 widget 的基本属性。您可以使用单个 元素在 XML 资源文件中定义 AppWidgetProviderInfo 对象,并将其保存在项目的 res/xml/ 文件夹中。

具体可见以下示例:

android:minWidth="40dp"

android:minHeight="40dp"

android:targetCellWidth="1"

android:targetCellHeight="1"

android:maxResizeWidth="250dp"

android:maxResizeHeight="120dp"

android:updatePeriodMillis="86400000"

android:description="@string/example_appwidget_description"

android:previewLayout="@layout/example_appwidget_preview"

android:initialLayout="@layout/example_loading_appwidget"

android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"

android:resizeMode="horizontal|vertical"

android:widgetCategory="home_screen"

android:widgetFeatures="reconfigurable|configuration_optional">

微件尺寸设置属性

默认的主屏幕根据定义了高度和宽度的单元格的网格在其窗口中放置 widget。大多数主屏幕仅允许微件采用网格单元的整数倍大小,例如,水平方向上为两个单元格,垂直方向上为三个单元格。

借助微件尺寸调整属性,您可以为微件指定默认大小,并提供微件大小的下限和上限。在此背景下,widget 的默认大小是指 widget 首次添加到主屏幕时所占的大小。

下表介绍了与 widget 大小调整相关的 属性:

属性和说明

targetCellWidth 和 targetCellHeight (Android 12)、minWidth 和 minHeight

从 Android 12 开始,targetCellWidth 和 targetCellHeight 属性以网格单元为单位指定 widget 的默认大小。在 Android 11 及更低版本中,这些属性会被忽略;如果主屏幕不支持基于网格的布局,这些属性也可以忽略。 minWidth 和 minHeight 属性指定 widget 的默认大小(以 dp 为单位)。如果微件的最小宽度或高度的值与单元格的尺寸不匹配,则这些值会向上舍入到最接近的单元格大小。

我们建议您同时指定这两组属性(targetCellWidth 和 targetCellHeight,以及 minWidth 和 minHeight),以便在用户设备不支持 targetCellWidth 和 targetCellHeight 时,您的应用可以回退到使用 minWidth 和 minHeight。如果支持,targetCellWidth 和 targetCellHeight 属性优先于 minWidth 和 minHeight 属性。

minResizeWidth 和 minResizeHeight

指定 widget 的绝对最小大小。这些值指定了微件小于什么尺寸会难以辨认或无法使用。使用这些属性,用户可以将微件的大小调整为小于默认微件大小。如果 minResizeWidth 属性的值大于 minWidth 或未启用水平大小调整,系统将忽略该属性。请参阅 resizeMode。同样,如果 minResizeHeight 属性的值大于 minHeight 或未启用垂直大小调整,系统也会忽略该属性。

maxResizeWidth 和 maxResizeHeight

指定 widget 的建议最大尺寸。如果这些值不是网格单元格尺寸的倍数,则会向上舍入为最接近的单元格大小。如果 maxResizeWidth 属性小于 minWidth 或未启用水平大小调整,系统将忽略该属性。请参阅 resizeMode。同样,如果 maxResizeHeight 属性的值大于 minHeight 或未启用垂直大小调整,系统将忽略该属性。

在 Android 12 中引入。

resizeMode

指定可以按什么规则来调整 widget 的大小。您可以使用此属性来让主屏幕 widget 在横轴上可调整大小、在纵轴上可调整大小,或者在这两个轴上均可调整大小。用户可轻触并按住微件以显示其大小调整手柄,然后拖动水平或垂直手柄以更改其在布局网格上的大小。resizeMode 属性的值包括 horizontal、vertical 和 none。如需将 widget 声明为在水平和垂直方向上均可调整大小,请使用 horizontal|vertical。

示例

为说明上表中的属性如何影响 widget 大小调整,假设有以下规范:

网格单元格的宽度为 30 dp,高度为 50 dp。

以下是属性规范:

android:minWidth="80dp"

android:minHeight="80dp"

android:targetCellWidth="2"

android:targetCellHeight="2"

android:minResizeWidth="40dp"

android:minResizeHeight="40dp"

android:maxResizeWidth="120dp"

android:maxResizeHeight="120dp"

android:resizeMode="horizontal|vertical" />

从 Android 12 开始:

使用 targetCellWidth 和 targetCellHeight 属性作为 widget 的默认大小。

默认情况下,该 widget 的大小为 2x2。该 widget 的大小可调整为最小 2x1 或最大 4x3。

Android 11 及更低版本:

使用 minWidth 和 minHeight 属性计算 widget 的默认大小。

默认宽度 = Math.ceil(80 / 30) = 3

默认高度 = Math.ceil(80 / 50) = 2

默认情况下,该 widget 的大小为 3x2。您可以将该 widget 调整为最小 2x1 或最大全屏。

注意: 实际的 widget 大小计算比上述公式更复杂,因为它还包括 widget 边距和网格单元格之间的间距。

其他 widget 属性

下表介绍了与 widget 大小调整以外的质量相关的 属性。

属性和说明

updatePeriodMillis

定义 widget 框架通过调用 onUpdate() 回调方法从 AppWidgetProvider 请求更新的频率。不能保证实际更新按此值正好准时发生,我们建议尽可能降低更新频率(不超过每小时一次),以节省电池电量。

如需查看选择合适更新周期的完整注意事项列表,请参阅优化 widget 内容更新。

initialLayout

指向用于定义 widget 布局的布局资源。

configure

定义在用户添加 widget 时启动的 activity,以便用户配置 widget 属性。请参阅允许用户配置 widget。

从 Android 12 开始,应用可以跳过初始配置。如需了解详情,请参阅使用 widget 的默认配置。

description

指定微件选择器要为您的微件显示的说明。在 Android 12 中引入。

previewLayout(Android 12)

和 previewImage(Android 11 及更低版本)

从 Android 12 开始,previewLayout 属性指定可缩放的预览,您会将其作为 XML 布局提供,该布局设置为微件的默认大小。理想情况下,指定为此属性的布局 XML 应与具有真实默认值的实际 widget 的布局 XML 相同。

在 Android 11 或更低版本中,previewImage 属性指定预览来描绘微件经过配置后是什么样子的,用户在选择应用微件时会看到该预览。如果未提供,则用户会看到应用的启动器图标。此字段对应于 AndroidManifest.xml 文件中 元素的 android:previewImage 属性。

注意:我们建议同时指定 previewImage 和 previewLayout 属性,以便在用户设备不支持 previewLayout 时,您的应用可以回退到使用 previewImage。如需了解详情,请参阅可缩放微件预览的向后兼容性。

autoAdvanceViewId

指定由 widget 的宿主自动跳转的 widget 子视图的视图 ID。

widgetCategory

声明 widget 是否可以显示在主屏幕 (home_screen) 和/或锁定屏幕 (keyguard) 上。对于 Android 5.0 及更高版本,只有 home_screen 有效。

widgetFeatures

声明 widget 支持的功能。例如,如果您希望微件在用户添加它时使用其默认配置,请同时指定 configuration_optional 和 reconfigurable 标志。这样会在用户添加微件后绕过启动配置 activity。用户以后仍可重新配置微件。

使用 AppWidgetProvider 类处理 widget 广播

AppWidgetProvider 类可处理 widget 广播,并根据 widget 生命周期事件更新 widget。以下部分介绍了如何在清单中声明 AppWidgetProvider,然后实现它。

在清单中声明 widget

首先,在应用的 AndroidManifest.xml 文件中声明 AppWidgetProvider 类,如以下示例所示:

android:exported="false">

android:resource="@xml/example_appwidget_info" />

元素需要 android:name 属性,该属性用于指定 widget 使用的 AppWidgetProvider。除非单独的进程需要向您的 AppWidgetProvider 广播,否则不得导出该组件,但通常情况下不会出现这种情况。

元素必须包含一个具有 android:name 属性的 元素。此属性指定 AppWidgetProvider 接受 ACTION_APPWIDGET_UPDATE 广播。这是您必须明确声明的唯一一项广播。AppWidgetManager 会根据需要自动将其他所有 widget 广播发送到 AppWidgetProvider。

元素指定 AppWidgetProviderInfo 资源,并且需要以下属性:

android:name:指定元数据名称。使用 android.appwidget.provider 将数据标识为 AppWidgetProviderInfo 描述符。

android:resource:指定 AppWidgetProviderInfo 资源位置。

实现 AppWidgetProvider 类

AppWidgetProvider 类扩展了 BroadcastReceiver,作为一个辅助类来处理 widget 广播。它仅接收与 widget 有关的事件广播,例如当更新、删除、启用和停用 widget 时发出的广播。当发生这些广播事件时,系统会调用以下 AppWidgetProvider 方法:

onUpdate()

调用此方法可以按 AppWidgetProviderInfo 中的 updatePeriodMillis 属性定义的时间间隔来更新 widget。如需了解详情,请参阅本页面中描述其他 widget 属性的表格。

当用户添加 widget 时也会调用此方法,因此它会执行基本设置,例如为 View 对象定义事件处理脚本,或启动作业以加载要在 widget 中显示的数据。不过,如果您声明的配置 activity 没有 configuration_optional 标志,则当用户添加 widget 时,系统不会调用此方法,但会调用它来执行后续更新。配置 activity 负责在配置完成后执行首次更新。如需了解详情,请参阅允许用户配置应用 widget。

最重要的回调是 onUpdate()。如需了解详情,请参阅本页中的使用 onUpdate() 类处理事件。

onAppWidgetOptionsChanged()

当首次放置 widget 时以及每当调整 widget 的大小时,会调用此方法。您可以使用此回调来根据微件的大小范围显示或隐藏内容。通过调用 getAppWidgetOptions() 获取大小范围,以及(从 Android 12 开始)widget 实例可采用的可能大小列表,该方法会返回包含以下各项的 Bundle:

OPTION_APPWIDGET_MIN_WIDTH:包含微件实例的宽度的下限(以 dp 为单位)。

OPTION_APPWIDGET_MIN_HEIGHT:包含微件实例的高度下限(以 dp 为单位)。

OPTION_APPWIDGET_MAX_WIDTH:包含微件实例的宽度上限(以 dp 为单位)。

OPTION_APPWIDGET_MAX_HEIGHT:包含微件实例的高度上限(以 dp 为单位)。

OPTION_APPWIDGET_SIZES:包含 widget 实例可采用的可能大小 (List) 的列表,以 dp 为单位。在 Android 12 中引入。

onDeleted(Context, int[])

每次从微件托管应用中删除微件时,都会调用此方法。

onEnabled(Context)

首次创建微件的实例时,会调用此方法。例如,如果用户添加了两个 widget 实例,则只有在首次添加时才会调用此方法。如果您需要打开一个新的数据库或执行只需要对所有 widget 实例执行一次的其他设置,则此方法非常合适。

onDisabled(Context)

当从微件宿主中删除微件的最后一个实例时,会调用此方法。您应使用此方法来清理在 onEnabled(Context) 中完成的所有工作,如删除临时数据库。

onReceive(Context, Intent)

针对每个广播调用此方法,并且是在上述各个回调方法之前调用。您通常不需要实现此方法,因为默认的 AppWidgetProvider 实现会过滤所有 widget 广播并视情况调用上述方法。

您必须在 AndroidManifest 中使用 元素将 AppWidgetProvider 类实现声明为广播接收器。如需了解详情,请参阅本页面中的在清单中声明 widget。

使用 onUpdate() 类处理事件

最重要的 AppWidgetProvider 回调是 onUpdate(),因为向宿主应用添加每个 widget 时都会调用它,除非您使用不含 configuration_optional 标志的配置 activity。如果您的 widget 接受任何用户互动事件,请在此回调中注册事件处理脚本。如果您的 widget 未创建临时文件或数据库,或者未执行其他需要清理的工作,则 onUpdate() 可能是您需要定义的唯一一个回调方法。

例如,如果您希望微件具有一个在用户点按时会启动 activity 的按钮,则可以使用以下 AppWidgetProvider 实现:

Kotlin

class ExampleAppWidgetProvider : AppWidgetProvider() {

override fun onUpdate(

context: Context,

appWidgetManager: AppWidgetManager,

appWidgetIds: IntArray

) {

// Perform this loop procedure for each widget that belongs to this

// provider.

appWidgetIds.forEach { appWidgetId ->

// Create an Intent to launch ExampleActivity.

val pendingIntent: PendingIntent = PendingIntent.getActivity(

/* context = */ context,

/* requestCode = */ 0,

/* intent = */ Intent(context, ExampleActivity::class.java),

/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE

)

// Get the layout for the widget and attach an onClick listener to

// the button.

val views: RemoteViews = RemoteViews(

context.packageName,

R.layout.appwidget_provider_layout

).apply {

setOnClickPendingIntent(R.id.button, pendingIntent)

}

// Tell the AppWidgetManager to perform an update on the current

// widget.

appWidgetManager.updateAppWidget(appWidgetId, views)

}

}

}

Java

public class ExampleAppWidgetProvider extends AppWidgetProvider {

public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

// Perform this loop procedure for each widget that belongs to this

// provider.

for (int i=0; i < appWidgetIds.length; i++) {

int appWidgetId = appWidgetIds[i];

// Create an Intent to launch ExampleActivity

Intent intent = new Intent(context, ExampleActivity.class);

PendingIntent pendingIntent = PendingIntent.getActivity(

/* context = */ context,

/* requestCode = */ 0,

/* intent = */ intent,

/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE

);

// Get the layout for the widget and attach an onClick listener to

// the button.

RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget_layout);

views.setOnClickPendingIntent(R.id.button, pendingIntent);

// Tell the AppWidgetManager to perform an update on the current app

// widget.

appWidgetManager.updateAppWidget(appWidgetId, views);

}

}

}

此 AppWidgetProvider 仅定义了 onUpdate() 方法,并使用该方法创建用于启动 Activity 的 PendingIntent,然后使用 setOnClickPendingIntent(int,

PendingIntent) 将其附加到 widget 的按钮。它包含一个遍历 appWidgetIds(这是一个 ID 数组,标识由此提供程序创建的每个 widget)中每个条目的循环。如果用户创建了微件的多个实例,则它们会全部同时更新。不过,对于微件的所有实例,只管理一个 updatePeriodMillis 时间表。例如,如果将更新时间表定义为每两小时更新一次,并且在第一个 widget 实例添加一小时后添加了第二个 widget 实例,那么这两个 widget 实例都会按照第一个 widget 实例定义的周期进行更新,而第二个更新周期会被忽略。这两个数据源每两小时更新一次,而不是每小时更新一次。

注意: 由于 AppWidgetProvider 是 BroadcastReceiver 的扩展,因此不能保证您的进程在回调方法返回结果后继续运行。如需了解广播生命周期,请参阅 BroadcastReceiver。如果您的 widget 设置过程可能需要几秒钟(例如在执行网络请求时),并且您要求您的操作过程继续进行,不妨考虑在 onUpdate() 方法中使用 WorkManager 启动一个 Task。在该任务中,您可以按照自己的时间表对 widget 执行更新,而不必担心由于应用无响应 (ANR) 错误而导致 AppWidgetProvider 关闭。

如需了解详情,请参阅 ExampleAppWidgetProvider.java 示例类。

接收 widget 广播 intent

AppWidgetProvider 是一个便利类。如果您希望直接接收 widget 广播,您可以实现自己的 BroadcastReceiver 或替换 onReceive(Context,Intent) 回调。您需要关注的 intent 如下所示:

ACTION_APPWIDGET_UPDATE

ACTION_APPWIDGET_DELETED

ACTION_APPWIDGET_ENABLED

ACTION_APPWIDGET_DISABLED

ACTION_APPWIDGET_OPTIONS_CHANGED

创建 widget 布局

您必须在 XML 中定义 widget 的初始布局,并将其保存在项目的 res/layout/ 目录中。如需了解详情,请参阅设计指南。

如果您熟悉布局,那么创建 widget 布局非常简单。不过,请注意,微件布局基于 RemoteViews,并不是每种布局或视图微件都受其支持。您无法使用自定义视图或 RemoteViews 支持的视图的子类。

RemoteViews 还支持 ViewStub,它是一个大小为零的不可见 View,您可以使用它在运行时以懒散的方式扩充布局资源。

支持有状态行为

Android 12 使用以下现有组件新增了对有状态行为的支持:

CheckBox

Switch

RadioButton

微件仍然无状态。您的应用必须存储状态并注册状态更改事件。

图 3. 有状态行为示例。

注意: 请务必使用 RemoteViews.setCompoundButtonChecked 显式设置当前选中状态,否则在拖动或调整 widget 大小时,可能会遇到意外结果。

以下代码示例展示了如何实现这些组件。

Kotlin

// Check the view.

remoteView.setCompoundButtonChecked(R.id.my_checkbox, true)

// Check a radio group.

remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2)

// Listen for check changes. The intent has an extra with the key

// EXTRA_CHECKED that specifies the current checked state of the view.

remoteView.setOnCheckedChangeResponse(

R.id.my_checkbox,

RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent)

)

Java

// Check the view.

remoteView.setCompoundButtonChecked(R.id.my_checkbox, true);

// Check a radio group.

remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2);

// Listen for check changes. The intent has an extra with the key

// EXTRA_CHECKED that specifies the current checked state of the view.

remoteView.setOnCheckedChangeResponse(

R.id.my_checkbox,

RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent));

提供两个布局:一个的目标设备搭载 Android 12 或更高版本(位于 res/layout-v31 中),另一个的目标设备搭载以前的 Android 11 或更低版本(位于默认的 res/layout 文件夹中)。

实现圆角

Android 12 引入了以下系统参数来设置微件圆角的半径:

system_app_widget_background_radius:微件背景的圆角半径,绝不会大于 28 dp。

内半径,可根据外半径和边衬区计算得出。

请参阅以下代码段:

/**

* Applies corner radius for views that are visually positioned [widgetPadding]dp inside of the

* widget background.

*/

@Composable

fun GlanceModifier.appWidgetInnerCornerRadius(widgetPadding: Dp): GlanceModifier {

if (Build.VERSION.SDK_INT < 31) {

return this

}

val resources = LocalContext.current.resources

// get dimension in float (without rounding).

val px = resources.getDimension(android.R.dimen.system_app_widget_background_radius)

val widgetBackgroundRadiusDpValue = px / resources.displayMetrics.density

if (widgetBackgroundRadiusDpValue < widgetPadding.value) {

return this

}

return this.cornerRadius(Dp(widgetBackgroundRadiusDpValue - widgetPadding.value))

}GlanceSnippets.kt

如需计算 widget 内部内容的合适半径,请使用以下公式:systemRadiusValue - widgetPadding

将内容剪裁为非矩形形状的 widget 应使用 @android:id/background 作为背景视图的视图 ID,并将 android:clipToOutline 设置为 true。

有关圆角的重要注意事项

第三方启动器和设备制造商可以替换 system_app_widget_background_radius 参数,使其小于 28 dp。

如果您的 widget 不使用 @android:id/background 或定义基于轮廓剪裁其内容的背景(将 android:clipToOutline 设置为 true),启动器会自动识别背景,并使用设置为系统半径的圆角矩形剪裁 widget。

非矩形形状需要包含在圆角矩形调整大小容器中,以免被剪裁。

从 Android 16 开始,system_app_widget_background_radius 的 AOSP 系统值为 24dp。启动器和设备制造商可能会将微件剪裁到 system_app_widget_background_radius。

widget 的内部内容必须具有足够的内边距,以支持高达 28dp 的 system_app_widget_background_radius 半径值,从而避免圆角裁剪内容。

为了确保微件与以前的 Android 版本兼容,我们建议您为 Android 12 定义自定义属性并使用自定义主题替换它们,如以下 XML 文件示例所示:

/values/attrs.xml

/values/styles.xml

/values-31/styles.xml

/drawable/my_widget_background.xml

android:shape="rectangle">

...

/layout/my_widget_layout.xml

...

android:background="@drawable/my_widget_background" />

Previus Post
英雄联盟平a是哪个键-英雄联盟平a是指哪个键

Copyright © 2088 英格兰世界杯预选赛_世界杯卡塔尔 - sctzjx.com All Rights Reserved.
友情链接