实现深色主题

尝试 Compose 方式
Jetpack Compose 是 Android 推荐的 UI 工具包。了解如何在 Compose 中使用主题。

图 1. 深色主题。

深色主题在 Android 10(API 级别 29)及更高版本中可用。它具有以下优势

  • 根据设备的屏幕技术,显着降低功耗。
  • 提高视力低下和对强光敏感的用户可见度。
  • 在弱光环境下更容易使用设备。

深色主题适用于 Android 系统 UI 和设备上运行的应用。

在 Android 10 及更高版本中,有三种方法可以启用深色主题

  • 使用系统设置,导航到**设置 > 显示 > 主题**以启用深色主题。
  • 启用后,使用快速设置磁贴从通知栏切换主题。
  • 在 Pixel 设备上,启用省电模式可同时启用深色主题。其他设备可能不支持此行为。

有关使用 WebView 组件将深色主题应用于基于 Web 的内容的说明,请参阅在 WebView 中使 Web 内容变暗

在您的应用中支持深色主题

要支持深色主题,请将应用的主题(通常位于res/values/styles.xml中)设置为继承自DayNight主题

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

您还可以使用Material Components 深色主题

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

这将应用的主要主题与系统控制的夜间模式标志绑定,并在启用时为应用提供默认的深色主题。

主题和样式

避免使用硬编码颜色或旨在在浅色主题下使用的图标。请改用主题属性或夜间限定资源。

两个主题属性对于深色主题最重要

  • ?android:attr/textColorPrimary:通用文本颜色。在浅色主题中接近黑色,在深色主题中接近白色。它包含禁用状态。
  • ?attr/colorControlNormal:通用图标颜色。它包含禁用状态。

我们建议使用Material Design Components,因为其颜色主题系统(例如主题属性?attr/colorSurface?attr/colorOnSurface)提供了对合适颜色的轻松访问。您可以在您的主题中自定义这些属性。

在应用内更改主题

您可以允许用户在应用运行时更改应用的主题。以下是推荐的选项

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

这些选项直接映射到AppCompat.DayNight模式

要切换主题,请执行以下操作

强制深色

Android 10 提供了强制深色,这是一个功能,开发人员可以使用它快速实现深色主题,而无需显式设置DayNight主题。

强制深色会分析浅色主题应用的每个视图,并在将其绘制到屏幕之前自动应用深色主题。您可以混合使用强制深色和原生实现来减少实现深色主题所需的时间。

应用必须通过在活动的主题中设置android:forceDarkAllowed="true"来选择加入强制深色。此属性在所有系统和 AndroidX 提供的浅色主题(例如Theme.Material.Light)上设置。当您使用强制深色时,请彻底测试您的应用并根据需要排除视图。

如果您的应用使用深色主题(例如Theme.Material),则不会应用强制深色。同样,如果您的应用的主题继承自DayNight主题,则由于自动主题切换,不会应用强制深色。

禁用视图上的强制深色

可以使用android:forceDarkAllowed布局属性或setForceDarkAllowed()控制特定视图上的强制深色。

Web 内容

有关在基于 Web 的内容中使用深色主题的信息,请参阅在 WebView 中使 Web 内容变暗。有关应用于 WebView 的深色主题示例,请参阅GitHub 上的 WebView 演示

最佳实践

以下部分提供了实施深色主题的最佳实践。

通知和小部件

对于您在设备上显示但没有直接控制的 UI 表面,请确保您使用的任何视图都反映主机应用的主题。两个示例是通知和启动器小部件。

通知

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

小部件和自定义通知视图

对于启动器小部件,或者如果您的应用使用自定义通知内容视图,请在浅色和深色主题上测试内容。

需要注意的一些常见陷阱包括以下内容

  • 假设背景颜色始终为浅色。
  • 硬编码文本颜色。
  • 在使用默认文本颜色时设置硬编码背景颜色。
  • 使用静态颜色的可绘制图标。

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

启动屏幕

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

删除任何硬编码颜色,例如以编程方式设置为白色的背景颜色。请改用?android:attr/colorBackground主题属性。

配置更改

当应用的主题通过系统设置或 AppCompat 更改时,它会触发uiMode配置更改。这意味着活动会自动重新创建。

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

应用可以通过声明每个Activity可以处理uiMode配置更改来处理深色主题的实现

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

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;
}