乐趣区

关于android:创造无限可能-在-Android-12-中使用-widget

本文是 “ 更新 Android 12 中 widget” 系列的第二篇文章。在上一部分 咱们探讨了通过一些简略的办法,为 APP 用户呈现出十分显性的视觉更新。在这篇文章中,咱们将一起理解一些更高级别的个性,这些性能会让您的 widget 更具交互性,更容易配置,并能在 Android 12 上出现更好的 UI 体验。

更简略的配置

在 Android 12 之前,从新设置 widget 意味着用户必须删除现有 widget,而后应用新配置从新增加。Android 12 在多个方面改良了 widget 的配置形式,从而帮忙用户采纳更简略的形式对 widget 进行个性化配置。

用户可从新设置原有 widget

可重组的 widget 容许用户对 widget 进行自定义设置。在 Android 12 中,用户将无需通过删除和从新增加 widget 来调整这些原有设定。

要应用这一性能,您需在 appwidget-provider 中把 widgetFeatures 属性设置为 reconfigurable。

xml/app_widget_info_checkbox_list.xml
<appwidget-provider
   android:configure="com.example.android.appwidget.ListWidgetConfigureActivity"
   android:widgetFeatures="reconfigurable"
   ... />
  • xml/app_widget_info_checkbox_list.xml

默认配置

如果您的 widget 依赖默认设置,在 Android 12 中您可跳过初始化操作,通过默认配置来设置 widget。

让咱们一起看下示例 widget 如何工作吧。在这个用例中,咱们心愿用户可能在两种不同的 widget 布局之间进行抉择,即 Grocery List 和 To-Do List。咱们会设定 Grocery List 为默认设置,这样用户就不须要执行配置步骤,除非他们想切换至 To-Do List。

要实现此用例,您能够存储用户选项,并在没有做出抉择操作的前提下,将 Grocery List 作为返回默认值。

ListAppWidget.kt
val layoutId = ListSharedPrefsUtil.loadWidgetLayoutIdPref(context, appWidgetId)
val remoteViews = if (layoutId == R.layout.widget_grocery_list) {
   // 以 dp 为单位,指定最大宽度和高度,// 并指定一个用于已指定尺寸的布局
   val viewMapping = mapOf(SizeF(150f, 150f) to constructRemoteViews(R.layout.widget_grocery_list), SizeF(250f, 150f) to constructRemoteViews(R.layout.widget_grocery_grid)
   )
       RemoteViews(viewMapping)
   } else {
       constructRemoteViews(layoutId)
   }
appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
  • ListAppWidget.kt

此时,该 widget 已被设定为 “ 提供默认配置 ”,您须要将 configuration_optional flag 设置为 widgetFeatures 属性。这个操作会跳过额定的配置步骤,您能够间接在用户的主屏幕上出现 widget。与此同时,请您确保增加 reconfigurable flag,以便用户后续能够更改失效的默认配置。

xml/app_widget_info_checkbox_list.xml
<appwidget-provider
   android:configure="com.example.android.appwidget.ListWidgetConfigureActivity"
   android:widgetFeatures="reconfigurable|configuration_optional"
   ... />
  • xml/app_widget_info_checkbox_list.xml

基于此更改,当用户将 widget 增加至主屏幕时,该 widget 会主动启用 Grocery List 布局。因为咱们把配置流动增加至 appwidget-providerconfigure 属性中,用户长按 widget 并点击编辑 / 从新设置按钮时,配置就会失效。

当用户配置该 widget 时,新的配置会被记录在 ListWidgetConfigureActivity 中。

ListWidgetConfigureActivity.kt
private fun onWidgetContainerClicked(@LayoutRes widgetLayoutResId: Int) {ListSharedPrefsUtil.saveWidgetLayoutIdPref(this, appWidgetId, widgetLayoutResId)
   // 配置流动有责任更新 app widget
   val appWidgetManager = AppWidgetManager.getInstance(this)
   ListAppWidget.updateAppWidget(this, appWidgetManager, appWidgetId)
   // 请您确保回传原始的 appWidgetId
   val resultValue = Intent()
   resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
   setResult(RESULT_OK, resultValue)
   finish()}
  • ListWidgetConfigureActivity.kt

全新 & 改良版 API

谈及 Android 零碎的设施,用户的抉择颇多,无论是手机、平板电脑、可折叠设施,还是其余类型的产品。Android 12 引入了欠缺的尺寸属性和更灵便的布局,这使得 widget 更易于定制,且在不同设施和屏幕尺寸上均有稳固牢靠的体现。

Widget 的尺寸限度

除了现有的 minWidthminHeighminResizeWidth 以及 minResizeHeight 以外,Android 12 还增加了新的 appwidget-provider 属性。

您能够应用新的 maxResizeWidthmaxResizeHeight 属性,来定义用户所可能调整的 widget 尺寸的最大高度和宽度。新的 targetCellWidthtargetCellHeight 属性可能定义设施主屏幕上的 widget 默认尺寸。

当定义了 targetCellWidthtargetCellHeight 属性后,搭载 Android 12 的设施将应用这些属性,而非 minWidthminHeight。搭载 Android 11 及以下版本的设施将持续应用 minWidthminHeight 属性。

提醒: targetCellWidth targetCellHeight 属性在 cells 中定义,而 maxResizeWidth maxResizeHeight 属性是在 dps 中定义的。

xml/app_widget_info_checkbox_list.xml
<appwidget-provider
   android:maxResizeWidth="240dp"
   android:maxResizeHeight="180dp"
   android:minWidth="180dp"
   android:minHeight="110dp"
   android:minResizeWidth="180dp"
   android:minResizeHeight="110dp"
   android:targetCellWidth="3"
   android:targetCellHeight="2"
   ... />
  • xml/app_widget_info_checkbox_list.xml

响应式布局

只管通过尺寸限度能够帮忙用户依据本身需要调整 widget 大小,但您可能更想依据 widget 的大小,提供不同的布局和内容类型。这也使零碎能在不唤醒利用的状况下,显示不同尺寸的 widget。

要做到这一点,首先您须要创立一组不同尺寸的布局,而后调用 updateAppWidget() 函数,并传入一组布局 (如下图所示)。当 widget 尺寸发生变化时,零碎会主动更改布局。

val viewMapping: MutableMap<SizeF, RemoteViews> = mutableMapOf()
// 以 dp 为单位,指定最大宽度和高度,// 并指定一个用于已指定尺寸的布局
val viewMapping = mapOf(SizeF(150f, 110f) to RemoteViews(
       context.packageName,
       R.layout.widget_grocery_list
   ),
   SizeF(250f, 110f) to RemoteViews(
       context.packageName,
       R.layout.widget_grocery_grid
   ),
)
appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(viewMapping))
//...

复合式按钮

在 Android 12 上,用户无需启动利用也能用 widget 做更多的事件啦!有了新的复合式按钮,您能够将 widget 变得更具交互性。这并不会扭转 widget 的无状态个性,但您能够增加一个监听器来察看状态的变动。您能够调用 RemoteResponse.fromPendingIntent(),并在状态发生变化时向监听器发送一个 PendingIntent

ItemsCollectionAppWidget.kt
remoteViews.setOnCheckedChangeResponse(
   R.id.item_switch,
   RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent)
)
  • ItemsCollectionAppWidget.kt

另一方面,如果 widget 有一个控件列表,不建议您在单我的项目 collection 上设置 PendingIntent,因为这会导致性能不佳。在这种状况下,您能够在该 collection 上设置一个 PendingIntent 模板,调起 RemoteResponse.fromFillInIntent(),并在状态发生变化时向监听器发送一个 fillInIntent

ItemsCollectionAppWidget.kt
remoteViews.setOnCheckedChangeResponse(
   R.id.item_switch,
   RemoteViews.RemoteResponse.fromFillInIntent(onCheckedChangeFillInIntent)
)
  • ItemsCollectionAppWidget.kt

Collection 中简化版的 RemoteViews

Android 12 引入了一个新的 API,可能简化发送单个 collection 去填充 widget 列表的过程。在此之前,如果您想通过我的项目的 collection 来填充 ListViewGridViewStackView 或其余视图,则须要执行 RemoteViewsService 返回 RemoteViewsFactory 的动作。有了新的 setRemoteAdapter() API,您便能够轻松应用外围 RemoteView 来发送 collection。咱们也正在做 androidx 的回传工作,以确保该 API 在旧 Android 版本上依然失效。

如果该 collection 不采纳常量设定布局,您能够通过 setViewTypeCount() 函数的形式,来设置此 collection 中 RemoteView 将应用的布局 ID 的最大值。

ItemsCollectionAppWidget.kt
remoteViews.setRemoteAdapter(
   R.id.items_list_view,
   RemoteViews.RemoteCollectionItems.Builder()
       .addItem(/* id= */ ID_1, RemoteViews(...))
       .addItem(/* id= */ ID_2, RemoteViews(...))
       //...
       .setViewTypeCount(MAX_NUM_DIFFERENT_REMOTE_VIEWS_LAYOUTS)
       .build())
  • ItemsCollectionAppWidget.kt

结语

请将现有的 widget 更新到 Android 12 吧!您会体验到一个有着全新外观和更具交互性的 widget。

当初您曾经在这篇文章中理解到可配置的、新的或是改良中的 API,请查阅咱们之前的推文《更新您的 widget 以适配 Android 12》,理解更新 widget 设计以及在 widget picker 中提供更好的用户体验的办法。如需更进一步,请查阅文章中提及的 代码示例。

如果您正在结构新的 widget,请您注意后续的公布。为了使结构新的 widget 更加简略,咱们始终在致力!

欢迎您 点击这里 向咱们提交反馈,或分享您喜爱的内容、发现的问题。您的反馈对咱们十分重要,感谢您的反对!

退出移动版