更新您的 widget 以适配 Android 12
Material You
https://material.io/blog/announcing-material-you
视觉变化
对于用户来说,毫无疑问最直观的视觉变化是风格和设计上的改变。更新可视元素,比如颜色和圆角,呈现出的外观会令用户耳目一新。增加这些修改,我们推荐您创建一个自定义的主题。
增加动态颜色
Material You 旨在提供更加个性化的用户体验。在 Android 12 中,动态颜色可以使您的微件与其它微件以及系统保持一致的风格。微件可以使用系统默认的主题 Theme.DeviceDefault.DayNight,并且在微件的 UI 元素中使用主题颜色属性。
△ Material Design 更新一览
腾讯视频链接
https://v.qq.com/x/page/l3248jb7ktt.htmlBilibili 视频链接
https://www.bilibili.com/video/BV13V41177zj/
对于 SDK 级别低于 31 的设备,您需要创建一个继承自 DeviceDefault 的自定义主题。
values/themes.xml
<style name="Theme.AppWidget.AppWidgetContainer"
parent="@android:style/Theme.DeviceDefault" />
对于 SDK 级别为 31 的设备,使用主题 DeviceDefault.DayNight 来创建自定义主题。
values-v31/themes.xml
<style name="Theme.AppWidget.AppWidgetContainer"
parent="@android:style/Theme.DeviceDefault.DayNight" />
values/themes.xml
https://github.com/android/user-interface-samples/blob/main/AppWidget/app/src/main/res/values/themes.xmlvalues-v31/themes.xml
https://github.com/android/user-interface-samples/blob/main/AppWidget/app/src/main/res/values-v31/themes.xml
或者,如果您的应用使用了 Material Components,您可以使用 Theme.MaterialComponents.DayNight 作为基础主题,而不是使用 Theme.DeviceDefault。
为了能够让您的微件可以动态适配系统颜色,您可以将该主题配置到您的微件上,并且在微件的其它视图上使用主题颜色属性。
layout/widget_checkbox_list_title_region.xml
...
<TextView android:id="@+id/checkbox_list_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:text="@string/grocery_list"
android:textColor="?android:attr/textColorPrimary" />
<ImageButton
android:layout_width="@dimen/widget_element_min_length"
android:layout_height="@dimen/widget_element_min_length"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:contentDescription="@string/add_button_grocery_list_content_description"
android:src="@drawable/ic_add_24"
android:tint="?android:attr/colorAccent" />
...
layout/widget_checkbox_list_title_region.xml
https://github.com/android/user-interface-samples/blob/main/AppWidget/app/src/main/res/layout/widget_checkbox_list_title_region.xml
△ 在浅色/深色主题中静态颜色与动态颜色的对比
圆角
从 Android 12 开始,圆角将自动应用于微件。这也意味着圆角会裁剪微件的部分内容。为了避免出现这样的问题,并且提供与其它微件和系统风格一致的外观和用户体验,您可以使用 system_app_widget_background_radius 在微件的背景添加圆角,使用 system_app_widget_inner_radius 在微件中的视图添加圆角。后者的值需要比 system_app_widget_background_radius 小 8dp。
system_app_widget_background_radius
https://developer.android.google.cn/reference/android/R.dimen#system_app_widget_background_radiussystem_app_widget_inner_radius
https://developer.android.google.cn/reference/android/R.dimen#system_app_widget_inner_radius
在添加上述修改时,请注意如果您的微件包含靠近角区域的内容,这些内容可能会被裁减掉。要解决该问题,您需要添加足够大的 padding 来避免微件的内容与圆角之间的冲突。
values/attrs.xml
<declare-styleable name="AppWidgetAttrs">
<attr name="appWidgetPadding" format="dimension" />
<attr name="appWidgetInnerRadius" format="dimension" />
<attr name="appWidgetRadius" format="dimension" />
</declare-styleable>
values/themes.xml
<style name="Theme.AppWidget.AppWidgetContainerParent"
parent="@android:style/Theme.DeviceDefault">
<!-- 微件的外轮廓的圆角半径 -->
<item name="appWidgetRadius">16dp</item>
<!-- widget 内部视图边缘的圆角半径。它的值为 8 dp 或者小于 appWidgetRadius -->
<item name="appWidgetInnerRadius">8dp</item>
</style>
<style name="Theme.AppWidget.AppWidgetContainer"
parent="Theme.AppWidget.AppWidgetContainerParent">
<!-- 增加 padding 来避免微件的内容与圆角冲突 -->
<item name="appWidgetPadding">16dp</item>
</style>
values-v31/themes.xml
<style name="Theme.AppWidget.AppWidgetContainerParent"
parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="appWidgetRadius">
@android:dimen/system_app_widget_background_radius</item>
<item name="appWidgetInnerRadius">
@android:dimen/system_app_widget_inner_radius</item>
</style>
values/styles.xml
<style name="Widget.AppWidget.AppWidget.Container"
parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:background">
?android:attr/colorBackground</item>
</style>
values/attrs.xml
https://github.com/android/user-interface-samples/blob/main/AppWidget/app/src/main/res/values/attrs.xmlvalues/themes.xml
https://github.com/android/user-interface-samples/blob/main/AppWidget/app/src/main/res/values/themes.xmlvalues-v31/themes.xml
https://github.com/android/user-interface-samples/blob/main/AppWidget/app/src/main/res/values-v31/themes.xmlvalues/styles.xml
https://github.com/android/user-interface-samples/blob/main/AppWidget/app/src/main/res/values/styles.xml
如果您的 minTargetSDK 小于 21,那么您需要提供适用于 SDK 版本 21 的 style,因为在可绘制对象上使用 android:attr/colorBackground 需要 SDK 版本至少为 21。
可绘制对象
https://developer.android.google.cn/guide/topics/graphics/drawables
至此您已经创建了主题,现在可以在微件的布局上设置样式了。
layout/widget_grocery_list.xml
<LinearLayout
style="@style/Widget.AppWidget.AppWidget.Container">
...
</LinearLayout>
layout/widget_grocery_list.xml
https://github.com/android/user-interface-samples/blob/main/AppWidget/app/src/main/res/layout/widget_grocery_list.xml
△ 对比原有风格、自动圆角效果以及带有圆角和 padding 的效果
过渡
当应用通过微件打开时,Android 12 提供了过渡效果。该过渡效果是由系统自动处理的,并且在旧版本的 Android 上不会出现。要启用该效果,您需要在微件布局根元素上指定一个 id,并设置它的值为 android:id/background。
<LinearLayout
android:id="@android:id/background">
...
</LinearLayout>
如果您的微件使用了 broadcast trampoline,也就是说您的微件在用户点击时创建了 PendingIntent,通过广播或者服务启动 Activity,那么在这种情况下,该过渡动画不会生效。
broadcast trampoline
https://developer.android.google.cn/about/versions/12/behavior-changes-12?hl=ca#notification-trampolines
微件选择器的优化
预览
<TextView
style="@style/Widget.AppWidget.Checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/widget_title_preview" />
<TextView
style="@style/Widget.AppWidget.Checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/widget_subject_preview" />
在布局上设置默认值可能会带来少量的延迟,因为占位的值会在实际值之前首先被启用。要避免该问题,您可以为预览创建一个独立的布局文件,并且启用自定义的预览主题。
<resources>
<!-- 声明属性-->
<attr name="widgetTitlePreview" format="string" />
<attr name="widgetSubjectPreview" format="string" />
<!-- 声明 style -->
<style name="Theme.MyApp.Widget"
parent="@style/Theme.DeviceDefault.DayNight.AppWidget">
<item name="widgetTitlePreview"></item>
<item name="widgetSubjectPreview"></item>
</style>
<style name="Theme.MyApp.Widget.Preview">
<item name="widgetTitlePreview">Preview Title</item>
<item name="widgetSubjectPreview">Preview Subject</item>
</style>
</resources>
创建预览主题后,您可以在布局中将它应用到预览元素上。
layout/my_widget_preview.xml
<LinearLayout ...>
<include layout="@layout/widget_header"
android:theme=”@style/Theme.MyApp.Widget.Preview” /></LinearLayout>
layout/my_widget_actual.xml
<LinearLayout ...>
<include layout="@layout/widget_header"
android:theme=”@style/Theme.MyApp.Widget” />
</LinearLayout>
最后,您需要将微件的布局设置为 appwidget-provider 的 previewLayout 属性。
xml/app_widget_info_checkbox_list.xml
<appwidget-provider
android:previewLayout="@layout/widget_grocery_list"
...
/>
xml/app_widget_info_checkbox_list.xml
https://github.com/android/user-interface-samples/blob/main/AppWidget/app/src/main/res/xml/app_widget_info_checkbox_list.xml
△ 对比静态预览效果与缩放预览效果
描述
您也可以设置 description 属性作为描述信息显示在微件选择器上。虽然这是可选项,但是提供描述信息可以帮助用户更好地了解微件的功能。
app_widget_info_checkbox_list.xml
<appwidget-provider
android:description="@string/app_widget_grocery_list_description"
...
/>
总结
在本文中,我们为您展示了如何更新微件设计并且在微件选择器中提供更好的用户体验。上述内容可以快速更新您的微件来适配 Android 12,您的用户可以看到非常直观的区别。
但这并不是全部。在下一篇文章中,我们将会了解新的 API,它可以使您的微件更加个性化,响应更灵敏且更具互动性。
推荐阅读