Google 致力于为黑人社区推动种族平等。查看具体举措

深色主题背景

Android 10 (API 级别 29) 及更高版本中提供深色主题背景。深色主题背景具有诸多优势:

  • 可大幅减少耗电量(具体取决于设备的屏幕技术)。
  • 为弱视以及对强光敏感的用户提高可视性。
  • 让所有人都可以在光线较暗的环境中更轻松地使用设备。

深色主题背景同时适用于 Android 系统界面和在设备上运行的应用。

在 Android 10 (API 级别 29) 及更高版本中,您可以通过以下三种方法启用深色主题背景:

  • 使用系统设置(Settings -> Display -> Theme)启用深色主题背景。
  • 使用“快捷设置”图块,从通知托盘中切换主题背景(启用后)。
  • 在 Pixel 设备上,选择“省电模式”将同时启用深色主题背景。其他原始设备制造商 (OEM) 不一定支持这种行为。

在应用中支持深色主题背景

如要支持深色主题背景,您必须将应用的主题背景(通常可在 res/values/styles.xml 中找到)设置为继承 DayNight 主题背景:

<style name="AppTheme" parent="Theme.AppCompat.DayNight">

您还可以使用 MaterialComponent 的深色主题背景

<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">

这会将应用的主要主题背景与系统控制的夜间模式标记相关联,并将应用的默认主题背景设置为深色主题背景(如果已启用)。

主题背景和样式

主题背景和样式应避免使用旨在于浅色主题背景下使用的硬编码颜色或图标。您应改用主题背景属性(首选)或适合在夜间使用的资源。

以下是需要了解的两个最重要的主题背景属性:

  • ?android:attr/textColorPrimary 这是一种通用型文本颜色。它在浅色主题背景下接近于黑色,在深色主题背景下接近于白色。该颜色包含一个停用状态。
  • ?attr/colorControlNormal 一种通用图标颜色。该颜色包含一个停用状态。

我们建议使用 Material Design 组件,因为您可以通过其颜色主题背景系统(例如主题背景属性 ?attr/colorSurface?attr/colorOnSurface)轻松获取合适的颜色。当然,您可以在主题背景中自定义这些属性。

更改应用内主题背景

您可能希望允许用户在应用运行时更改其主题背景。应用可以让用户选择不同的主题背景。

当应用在搭载 Android 9 或更低版本的设备上运行时,推荐的主题背景选项是:

  • 浅色
  • 深色
  • 由省电模式设置(推荐的默认选项)

应用在 Android 10 (API 级别 29) 及更高版本上运行时,推荐的选项有所不同,目的是允许用户替换系统默认设置:

  • 浅色
  • 深色
  • 系统默认(推荐的默认选项)

请注意,如果用户选择“Light”,省电模式不会更改该设置。

每个选项直接映射到以下某个 AppCompat.DayNight 模式:

如要切换主题背景,请调用 AppCompatDelegate.setDefaultNightMode()

Force Dark

Android 10 提供 Force Dark 功能。一如其名,此功能可让开发者快速实现深色主题背景,而无需明确设置 DayNight 主题背景。

如果您的应用采用浅色主题背景,则 Force Dark 会分析应用的每个视图,并在相应视图在屏幕上显示之前,自动应用深色主题背景。有些开发者会混合使用 Force Dark 和本机实现,以缩短实现深色主题背景所需的时间。

应用必须选择启用 Force Dark,方法是在其主题背景中设置 android:forceDarkAllowed="true"。此属性会在所有系统及 AndroidX 提供的浅色主题背景(例如 Theme.Material.Light)上设置。使用 Force Dark 时,您应确保全面测试应用,并根据需要排除视图。

如果您的应用使用深色主题背景(例如Theme.Material),则系统不会应用 Force Dark。同样,如果应用的主题背景继承自 DayNight 主题背景,则系统不会应用 Force Dark,因为会自动切换主题背景。

在视图上停用 Force Dark

您可以通过 android:forceDarkAllowed 布局属性或 setForceDarkAllowed() 在特定视图上控制 Force Dark。

最佳实践

通知和微件

对于在设备上显示但您并不直接控制的界面,请务必确保您使用的所有视图都反映托管应用的主题背景。通知和启动器微件就是两个很好的示例。

通知

使用系统提供的通知模板(例如 MessagingStyle)。这意味着,系统将负责确保应用正确的视图样式。

微件和自定义通知视图

对于启动器微件,或者如果您的应用使用自定义通知内容视图,请务必确保针对浅色和深色主题背景测试内容。

需要注意的常见陷阱:

  • 假设背景颜色始终为浅色
  • 对文本颜色进行硬编码
  • 设置硬编码背景颜色,同时使用默认文本颜色
  • 使用采用静态颜色的可绘制图标

在所有这些情况下,请使用相应的主题背景属性,而不是硬编码颜色。

启动屏幕

如果您的应用有自定义启动屏幕,则您可能需要对其进行修改,以便其可以反映所选的主题背景。

移除所有硬编码颜色(例如指向颜色可能为白色的任何背景颜色),改用 ?android:attr/colorBackground 主题背景属性。

请注意,采用深色主题背景的 android:windowBackground 可绘制对象仅适用于 Android Q。

配置变更

当应用的主题背景发生更改(无论是通过系统设置还是 AppCompat)时,会触发 uiMode 配置变更。这意味着系统会自动重新创建 Activity。

在某些情况下,您可能希望应用处理配置变更。例如,您可能希望延迟配置变更时间,因为设备正在播放视频。

应用可以声明,每个 Activity 都可以处理 uiMode 配置变更,以自行处理深色主题背景的实现:

<activity
    android:name=".MyActivity"
    android:configChanges="uiMode" />

当某个 Activity 声明它会处理配置变更时,系统会在出现主题背景变更时调用该 Activity 的 onConfigurationChanged() 方法。

如要检查当前采用的是哪种主题背景,应用可以运行如下代码:

Kotlin

val currentNightMode = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
when (currentNightMode) {
    Configuration.UI_MODE_NIGHT_NO -> {} // Night mode is not active, we're using the light theme
    Configuration.UI_MODE_NIGHT_YES -> {} // Night mode is active, we're using dark theme
}

Java

int currentNightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
    case Configuration.UI_MODE_NIGHT_NO:
        // Night mode is not active, we're using the light theme
        break;
    case Configuration.UI_MODE_NIGHT_YES:
        // Night mode is active, we're using dark theme
        break;
}