深色主题适用于 Android 10(API 级别 29)及更高版本。它具有以下优势:
- 可大幅减少耗电量,具体取决于设备的屏幕技术。
- 为弱视以及对强光敏感的用户提高可视性。
- 可让您在光线较暗的环境中更轻松地使用设备。
深色主题会应用于 Android 系统界面和设备上运行的应用。
在 Android 10 及更高版本中,您可以通过以下三种方式启用深色主题:
- 通过依次前往设置 > 显示 > 主题,使用系统设置来启用深色主题。
- 启用“快捷设置”功能块后,可从通知栏中切换主题。
- 在 Pixel 设备上,启用省电模式可同时启用深色主题。其他设备可能不支持此行为。
有关使用 WebView 组件对基于网络的内容应用深色主题的说明,请参阅使用 WebView 调暗网页内容的颜色。
在应用中支持深色主题
如需支持深色主题,请将应用的主题(通常可在 res/values/styles.xml
中找到)设置为继承 DayNight
主题:
<style name="AppTheme" parent="Theme.AppCompat.DayNight">
您还可以使用 Material 组件深色主题:
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
这会将应用的主要主题与系统控制的夜间模式标志相关联,并在启用后为应用提供默认的深色主题。
主题和样式
避免使用专用于浅色主题的硬编码颜色或图标。请改用主题属性或适合夜间使用的资源。
对于深色主题,有两个主题属性最为重要:
?android:attr/textColorPrimary
:一种通用文本颜色。它在浅色主题下接近于黑色,在深色主题下接近于白色。它包含一个停用状态。?attr/colorControlNormal
:通用图标颜色。它包含一个停用状态。
我们建议您使用 Material Design 组件,因为通过它的颜色主题系统(如主题属性 ?attr/colorSurface
和 ?attr/colorOnSurface
)可以轻松获取合适的颜色。您可以在主题中自定义这些属性。
更改应用内主题
您可以允许用户在应用运行时更改其主题。以下是推荐的选项:
- 浅色
- 深色
- 系统默认设置(推荐的默认选项)
这些选项直接映射到 AppCompat.DayNight
模式:
浅色:
MODE_NIGHT_NO
。深色:
MODE_NIGHT_YES
。系统默认设置:
MODE_NIGHT_FOLLOW_SYSTEM
。
如需切换主题,请执行以下操作:
在 API 级别 31 及更高版本中,使用
UiModeManager#setApplicationNightMode
告知系统您的应用运行的是哪个主题。这样,系统便可以在启动画面期间匹配主题。在 API 级别 30 及更低版本中,请使用
AppCompatDelegate.setDefaultNightMode()
切换主题。
Force Dark
Android 10 提供了 Force Dark,此功能可让开发者快速实现深色主题,而无需明确设置 DayNight
主题。
Force Dark 会分析您采用浅色主题的应用的每个视图,并在相应视图在屏幕上显示之前,自动应用深色主题。您可以混合使用 Force Dark 和本机实现,以缩短实现深色主题所需的时间。
应用必须通过在 activity 的主题中设置 android:forceDarkAllowed="true"
来选择启用 Force Dark。此属性会在系统和 AndroidX 提供的所有浅色主题(例如 Theme.Material.Light
)上设置。使用 Force Dark 时,请全面测试应用,并根据需要排除视图。
如果您的应用使用深色主题(例如 Theme.Material
),则系统不会应用 Force Dark。同样,如果应用的主题继承自 DayNight
主题,系统也不会应用 Force Dark,因为会自动切换主题。
在视图上停用 Force Dark
您可以通过 android:forceDarkAllowed
布局属性或 setForceDarkAllowed()
在特定视图上控制 Force Dark。
Web 内容
如需了解如何在基于网络的内容中使用深色主题,请参阅使用 WebView 调暗网页内容的颜色。如需查看适用于 WebView 的深色主题的示例,请参阅 GitHub 上的 WebView 演示。
最佳实践
下面几个部分介绍了实现深色主题的最佳做法。
通知和微件
对于在设备上显示但您并不直接控制的界面,请确保您使用的所有视图都能反映托管应用的主题。通知和启动器 widget 是两个示例。
通知
使用系统提供的通知模板,例如 MessagingStyle
。这意味着,系统负责应用正确的视图样式。
微件和自定义通知视图
对于启动器 widget,或者如果您的应用使用自定义通知内容视图,请同时针对浅色主题和深色主题测试内容。
需要注意的常见误区包括:
- 假设背景颜色始终为浅色。
- 对文本颜色进行硬编码。
- 使用默认文本颜色时设置硬编码背景颜色。
- 使用采用静态颜色的可绘制图标。
在所有这些情况下,请使用适当的主题属性,而不是硬编码颜色。
启动屏幕
如果您的应用具有自定义启动屏幕,您可能需要对其进行修改,以使其反映所选主题。
移除所有硬编码颜色,例如以编程方式设置为白色的背景颜色。请改用 ?android:attr/colorBackground
主题属性。
配置变更
当应用的主题发生变化(无论是通过系统设置还是 AppCompat)时,会触发 uiMode
配置变更。这意味着系统会自动重新创建 activity。
在某些情况下,您可能希望应用来处理配置变更。例如,您可能希望延迟配置变更时间,因为正在播放视频。
应用可以通过声明每个 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; }