向应用添加动态配色

1. 准备工作

在此 Codelab 中,您将更新起始应用(一款小费计算器应用),以使用 Material Design 3 中的新功能,从而根据用户的壁纸动态设置应用界面的主题。以下是应用应用动态配色后的几个屏幕截图。您还将了解一些其他场景,以便控制颜色的应用方式。

前提条件

开发者应

  • 熟悉 Android 中的基本主题设置概念
  • 能够轻松修改应用的主题

学习内容

  • 如何区分现有 Material 组件和 Material 3 主题
  • 如何将主题更新为 Material 3
  • 如何使用我们的工具创建主题并应用主题
  • 主题属性之间的关系

所需条件

2. 起始应用概览

Tip Time 应用是一款小费计算器应用,提供各种自定义小费的选项。它是我们“使用 Kotlin 进行 Android 开发的基础知识”培训课程中的一个示例应用。

59906a9f19d6b804.png

3. 更新 Gradle 依赖项

在更新实际主题并应用动态颜色之前,需要在应用的 build.gradle 文件中进行一些更改。

在依赖项部分中,确保 material 库为 1.5.0-alpha04 或更高版本:

dependencies {
    // ...
    implementation 'com.google.android.material:material:<version>'
}

在 android 部分,更改 compileSdkVersion 和 targetSdkVersion

到 31 或更高版本:

android {
    compileSdkVersion 31
    // ...

    defaultConfig {
        // ...
        targetSdkVersion 31
    }
}

这些说明假定应用具有相对较新的依赖项。对于尚未使用 Material 或使用较旧版本的应用,请查看 Material Design Components for Android“使用入门”文档中的说明。

无论您在何处创建了主题,都请将 Theme.MaterialComponents.* 的引用更改为 Theme.Material3.*。某些样式在 Material3 命名空间中尚无新样式,但大多数组件在父主题更新为 Theme.Material3.* 后仍会继承新样式。从下图中可以看出,按钮现在采用了新的圆角主题。

在下面的主题文件示例中,唯一更改的是父主题。稍后,我们将完全替换此主题。部分颜色属性已过时,我们创建的部分自定义样式现在已成为 Material3 中的标准样式,但我们希望您能

themes.xml

<style name="Theme.TipTime" parent="Theme.Material3.Light">
   <!-- Primary brand color. -->
   <item name="colorPrimary">@color/green</item>
   <item name="colorPrimaryVariant">@color/green_dark</item>
   <item name="colorOnPrimary">@color/white</item>
   <!-- Secondary brand color. -->
   <item name="colorSecondary">@color/blue</item>
   <item name="colorSecondaryVariant">@color/blue_dark</item>
   <item name="colorOnSecondary">@color/black</item>
   <!-- Status bar color. -->
   <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
   <!-- For text input fields -->
   <item name="textInputStyle">@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox</item>
   <!-- For radio buttons -->
   <item name="radioButtonStyle">@style/Widget.TipTime.CompoundButton.RadioButton</item>
   <!-- For switches -->
   <item name="switchStyle">@style/Widget.TipTime.CompoundButton.Switch</item>
</style>

f91e2acbac7cd469.png

4. 了解颜色主题和颜色角色

Material 3 颜色系统采用有条理的方法将颜色应用到界面。Theme.AppCompat 中的许多属性仍在被使用。不过,Theme.MaterialComponents.* 中添加了更多属性,Theme.Material3.* 中添加的属性甚至更多,因此请务必检查应用的所有界面,确保没有未实现的属性从基本主题中泄露出来。

了解颜色角色

在 Material 3 主题中,与颜色相关的属性超过 20 个。这乍看之下可能令人怯步,但实际上只有几种关键颜色与相同的 4-5 种颜色角色相结合,才能创建派生颜色。

这些颜色组包括:

  • 主要颜色,应用的主要颜色
  • 次要颜色,应用的次要颜色
  • 第三色,即与主色和辅色互补的第三种颜色
  • 错误,用于错误文本和对话框
  • 背景
  • Surface、SurfaceVariant、Surface Inverse

主色、辅色、第三色和错误色的角色如下:

<基本颜色>

基本色

在<base color>上

显示在基础颜色上的图标和文字的颜色

<base color>容器

派生自基础颜色,用于按钮、对话框等

在<base color>Container 上

容器中图标和文字的颜色

例如,Material 3 中采用默认样式的悬浮操作按钮使用 Primary 作为其基础颜色,因此它使用 primaryContainer 作为按钮的背景颜色,并使用 onPrimaryContainer 作为其内容颜色。

手动自定义主题时,您至少应验证所更改的每个基本颜色的 on<base color> 属性是否仍然清晰可辨。

最佳实践是同时调整颜色组中的所有角色,以确保从基础到应用都没有伪影。

背景和 Surface 基本颜色通常具有两种角色:一种是基本颜色本身,另一种是显示在其上的图标或文字的 on<base color>

5. 使用 Material Theme Builder 创建 Material 3 主题

借助 Material Theme Builder,您可以轻松构建自定义配色方案,使用其内置的代码导出功能迁移到 M3 颜色系统,并充分利用动态颜色。了解详情:material.io/material-theme-builder

Tip Time 应用主题包含多个组件样式,但大多数样式都是 Material 3 主题中的默认样式。我们需要关注的两个关键颜色只有 Primary 和 Secondary。

这些颜色分别对应于绿色主色 (#1B5E20) 和蓝色辅色 (#0288D1)。

您可以将这些颜色输入到 Material Theme Builder 中,然后导出完整的主题(假设其他地方有指向完整概览的链接)。

请注意,您输入的颜色可能会发生色调变化,以适应颜色生成算法并确保颜色互补且易于辨识。

以下是输入自定义颜色时生成的部分值。

7f6c5a33f5233811.png

6. 使用 Material Theme Builder 导出文件

导出归档包含具有各自 themes.xml 文件的 values 和 values-night/ 目录,分别对应于浅色和深色主题。所有颜色都在 values/colors.xml 中定义。

f66a64db2989a260.png

这些文件可以按原样复制,但您必须更改 AndroidManifest.xml 中的主题名称或主题文件中的主题名称,以使两者保持一致。工具中的默认名称为 AppTheme。

重启应用,界面看起来几乎完全一样。一个值得注意的变化是开关和单选按钮,其选中状态现在使用主要颜色中的色调进行主题化,而不是次要颜色。在较大的应用中,您可能需要重新考虑某些设计。

38a50ada47fd5ea4.png

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.tiptime">

   <application ...>
       <activity android:name=".MainActivity"
           android:exported="true">
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />

               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
       </activity>
   </application>

</manifest>

7. 添加动态配色

使用合适的 Material 3 主题后,只需添加少量代码,即可使界面具有动态效果。

借助动态颜色 API,您可以将动态颜色应用于所有 activity

在应用、各个 activity 或各个视图或 fragment 中。适用于

此应用,我们将全局应用动态配色。

创建 Application 类文件

class TipTimeApplication: Application() {
    override fun onCreate() {
        // Apply dynamic color
        DynamicColors.applyToActivitiesIfAvailable(this)
    }
}

我们需要在 Android 清单中引用以下新创建的文件:

AndroidManifest.xml

< application android name=".TipTimeApplication
<!--- Other existing attributes –>

</application >

在 Android 12 及更高版本的系统中,系统会检查用户默认方案的壁纸,以生成多个色调调色板。这些调色板中的值用于创建 ThemeOverlay

DynamicColors 类会注册一个 ActivityLifecycleCallbacks,该 ActivityLifecycleCallbacks 会拦截 ActivityPreCreated 以应用系统创建的动态主题叠加层或您提供的叠加层。

eba71f96f4ba9cdf.png

8. 应用自定义主题叠加层

我们的工具可以导出主题叠加层,但如果您要替换的属性数量较少,也可以手动创建主题叠加层。

主题叠加层旨在与另一个主题搭配使用,并且仅提供将在基础主题之上更改的值。

假设出于某种原因(可能是品牌推广),我们需要将主色调设为红色。我们可以使用以下文件和属性来实现这一点。

colors.xml

<resources>
    <color name="overlay_light_primary">#9C4146</color>
    <color name="overlay_light_onPrimary">#FFFFFF</color> 
    <color name= "overlay_light_primaryContainer">#FFDADB</color>
    <color name="overlay_light_onPrimaryContainer">#400008</color>
</resources >

themes_overlays.xml

<style name="AppTheme.Overlay" parent="ThemeOverlay.Material3.DynamicColors.Light">
    <item name="colorPrimary">@color/overlay_light_primary</item>
    <item name="colorOnPrimary">@color/overlay_light_onPrimary</item> 
    <item name="colorPrimaryContainer">@color/overlay_light_primaryContainer</item> 
    <item name="colorOnPrimaryContainer">@color/overlay_light_onPrimaryContainer<item>
</style>

对于上述代码,Android 12 将应用动态浅色主题,并在其上叠加您的更改。或者,您也可以使用任何有效的 ThemeOverlay 作为父级,包括以下任一 ThemeOverlay:

ThemeOverlay.Material3.Light

ThemeOverlay.Material3.Dark

ThemeOverlay.Material3.DayNight ThemeOverlay.Material3.DynamicColors.Dark

ThemeOverlay.Material3.DynamicColors.DayNight

如需使用此主题叠加层而非 Material 默认主题,请将对 DynamicColors.applyToActivitiesIfAvailable 的调用更改为:

DynamicColors.applyToActivitiesIfAvailable(this, R.style.AppTheme_Overlay)

d87020776782036f.png

9. 向自定义属性添加动态颜色

到目前为止,我们已替换 Material 3 主题中已有的属性。在动态配色中,我们还有一种可能的情况,即可能有一个或多个需要分配的自定义属性。

当应用选择启用动态配色时,它将获得 5 个色调调色板的访问权限,包括 3 个强调色调色板和 2 个中性色调色板,大致具有以下作用:

system_accent1

主要色调

system_accent2

次要色调

system_accent3

三级色调

system_neutral1

中性背景和表面

system_neutral2

中性表面和轮廓

每种调色板都有一定数量的色调步数,从白色

到黑色:0、10、50、100、200、300、400、500、600、700、800、900、1000。

在为动态配色设计界面时,您应减少对特定颜色的考虑,而更多地考虑该组件的色调和亮度与设计系统中其他组件的关系。

假设您希望使用次要强调色调色板为图标设置主题,并添加了一个属性来为图标着色,attrs.xml 中的条目如下所示。

attrs.xml

<resources>
    <attr name="iconColor" format="color" />
</resources>

您的主题叠加层可能如下所示:

<style name="AppTheme.Overlay" parent="ThemeOverlay.Material3.DynamicColors.DayNight"> 
<item name="iconColor">@android:color/system_accent2_600</item>
</style>

当您重新安装应用并更改壁纸时,应用会采用该辅助调色板。

11ef0035702640d9.png

264b2c2e74c5f574.png

这些调色板是 Android 12 (API 31) 特有的,因此您需要将相关文件放置在带有 -v31 后缀的文件夹中,除非您的应用的最低 SDK 设置为 31 或更高。

10. 总结

在此 Codelab 中,您已能够:

  • 添加依赖项以将主题升级到 Material 3。
  • 了解新的颜色组和角色。
  • 了解如何从静态主题迁移到动态配色。
  • 了解如何使用主题叠加层以及如何使用动态配色来设置自定义主题属性。