This article is the second article in the "Update Android 12 widgets" series. In the part of we explored some simple methods to present a very dominant visual update for APP users. In this article, we will learn about some higher-level features together that will make your widget more interactive, easier to configure, and present a better UI experience on Android 12.
Simpler configuration
Before Android 12, resetting the widget meant that the user had to delete the existing widget and then add it again with the new configuration. Android 12 has improved the configuration of widgets in many aspects, thereby helping users to personalize widgets in a simpler way.
users can reset the original widget
The reconfigurable widget allows users to customize the widget settings. In Android 12, users will not need to delete and re-add widgets to adjust these original settings.
To use this function, you need to set the widgetFeatures
property to reconfigurable appwidget-provider
xml/app_widget_info_checkbox_list.xml
<appwidget-provider
android:configure="com.example.android.appwidget.ListWidgetConfigureActivity"
android:widgetFeatures="reconfigurable"
... />
Default configuration
If your widget relies on the default settings, you can skip the initialization operation in Android 12 and set the widget through the default configuration.
Let's take a look at how the example widget works. In this use case, we want users to be able to choose between two different widget layouts, namely Grocery List and To-Do List. We will set Grocery List as the default setting so that users do not need to perform configuration steps unless they want to switch to To-Do List.
To achieve this use case, you can store user options and return the Grocery List as the default value without making a selection operation.
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)
At this point, the widget has been set to "provide default configuration", and you need to set the configuration_optional
flag to the widgetFeatures
attribute. This operation will skip the extra configuration step, and you can directly present the widget on the user's home screen. At the same time, please make sure to add the reconfigurable
flag so that the user can change the effective default configuration later.
xml/app_widget_info_checkbox_list.xml
<appwidget-provider
android:configure="com.example.android.appwidget.ListWidgetConfigureActivity"
android:widgetFeatures="reconfigurable|configuration_optional"
... />
Based on this change, when a user adds a widget to the home screen, the widget will automatically enable the Grocery List layout. As we add configuration activities to appwidget-provider
of configure
attribute, when users press widget and click Edit / Reset button, the configuration will take effect.
When the user configures the widget, the new configuration will be recorded in 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()
}
New & Improved API
When it comes to Android system devices, users have a lot of choices, whether it's mobile phones, tablets, foldable devices, or other types of products. Android 12 introduces complete size attributes and more flexible layouts, which makes widgets easier to customize, and has stable and reliable performance on different devices and screen sizes.
Widget size limit
In addition to the existing minWidth
, minHeigh
, minResizeWidth
and minResizeHeight
, Android 12 also adds a new appwidget-provider
attribute.
You can use the new maxResizeWidth
and maxResizeHeight
attributes to define the maximum height and width of the widget size that users can adjust. The new targetCellWidth
and targetCellHeight
attributes can define the default size of the widget on the main screen of the device.
When the targetCellWidth
and targetCellHeight
attributes are defined, devices equipped with Android 12 will use these attributes instead of minWidth
and minHeight
. Devices with Android 11 and below will continue to use the minWidth
and minHeight
attributes.
Tip: targetCellWidth and targetCellHeight attributes defined in the cells, whereas maxResizeWidth and maxResizeHeight properties are defined in the 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"
... />
Responsive layout
Although the size restriction can help users adjust the size of the widget according to their own needs, you may prefer to provide different layouts and content types based on the size of the widget. This also enables the system to display widgets of different sizes without waking up the application.
To do this, you first need to create a set of layouts of different sizes, and then call the updateAppWidget()
function and pass in a set of layouts (as shown in the figure below). When the widget size changes, the system will automatically change the layout.
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))
//...
Compound button
On Android 12, users can do more things with widgets without launching the app! With the new compound button, you can make the widget more interactive. This does not change the stateless nature of the widget, but you can add a listener to observe the state changes. You can call RemoteResponse.fromPendingIntent()
PendingIntent
to the listener when the state changes.
ItemsCollectionAppWidget.kt
remoteViews.setOnCheckedChangeResponse(
R.id.item_switch,
RemoteViews.RemoteResponse.fromPendingIntent(
onCheckedChangePendingIntent
)
)
On the other hand, if the widget has a list of controls, it is not recommended that you set PendingIntent
on the single-item collection, because this will cause poor performance. In this case, you can set a PendingIntent
template on the collection, call up RemoteResponse.fromFillInIntent()
fillInIntent
to the listener when the status changes.
ItemsCollectionAppWidget.kt
remoteViews.setOnCheckedChangeResponse(
R.id.item_switch,
RemoteViews.RemoteResponse.fromFillInIntent(
onCheckedChangeFillInIntent
)
)
simplified version of RemoteViews in the Collection
Android 12 introduces a new API that can simplify the process of sending a single collection to populate the widget list. Before that, if you want to fill ListView
, GridView
, StackView
or other views through the collection of items, you need to perform the action of RemoteViewsService
returning RemoteViewsFactory
With the new setRemoteAdapter()
API, you can easily use the core RemoteView
to send collections. We are also doing the return work of androidx to ensure that the API is still valid on the old Android version.
If the collection does not use constant setting layouts, you can use the setViewTypeCount()
function to set the maximum layout ID that will be used by RemoteView
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()
)
Conclusion
Please update your existing widgets to Android 12! You will experience a widget with a new look and more interaction.
Now that you have learned about the configurable, new or improved API in this article, please refer to our previous tweet " update your widget to adapt to Android 12 " to learn about the updated widget design and Provide a better user experience method in widget picker. If you need to go further, please refer to the code sample mentioned in the article.
If you are constructing a new widget, please pay attention to subsequent releases. In order to make it easier to construct a new widget, we have been working hard!
You are welcome to click here to submit feedback to us, or share your favorite content, problems found. Your feedback is very important to us, thank you for your support!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。