
深色主题在 Android 10(API 等级 29)及更高版本中提供。它具有以下优势:
- 大幅降低功耗,具体取决于设备的屏幕技术。
- 提高了视力低下和对强光敏感的用户的可见性。
- 使在弱光环境下更容易使用设备。
深色主题适用于 Android 系统界面和在设备上运行的应用。
在 Android 10 及更高版本中,有三种启用深色主题的方式:
- 通过依次导航到设置 > 显示 > 主题来使用系统设置启用深色主题。
- 启用后,可以使用快速设置磁贴从通知托盘切换主题。
- 在 Pixel 设备上,启用 Battery Saver 模式可同时启用深色主题。其他设备可能不支持此行为。
有关使用 WebView 组件将深色主题应用于基于网页的内容的说明,请参阅在 WebView 中将网页内容变暗。
在应用中支持深色主题
要支持深色主题,请将您的应用主题(通常位于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
模式:
浅色:
MODE_NIGHT_NO
。深色:
MODE_NIGHT_YES
。系统默认:
MODE_NIGHT_FOLLOW_SYSTEM
。
要切换主题,请执行以下操作:
在 API 等级 31 及以上版本中,使用
UiModeManager#setApplicationNightMode
让系统知道您的应用正在运行哪个主题。这样系统可以在启动画面期间匹配主题。在 API 等级 30 及以下版本中,使用
AppCompatDelegate.setDefaultNightMode()
切换主题。
强制深色
Android 10 提供了一种称为强制深色的功能,供开发者快速实现深色主题,而无需显式设置 DayNight
主题。
强制深色会分析您的浅色主题应用的每个视图,并在绘制到屏幕之前自动应用深色主题。您可以混合使用强制深色和原生实现,以减少实现深色主题所需的时间。
应用必须在 activity 的主题中设置 android:forceDarkAllowed="true"
来选择加入强制深色。此属性在所有系统和 AndroidX 提供的浅色主题(例如 Theme.Material.Light
)上都已设置。当您使用强制深色时,请彻底测试您的应用,并根据需要排除视图。
如果您的应用使用深色主题(例如 Theme.Material
),则不会应用强制深色。类似地,如果您的应用主题继承自 DayNight
主题,由于自动主题切换,也不会应用强制深色。
在视图上禁用强制深色
可以使用 android:forceDarkAllowed
布局属性或setForceDarkAllowed()
在特定视图上控制强制深色。
网页内容
有关在基于网页的内容中使用深色主题的信息,请参阅在 WebView 中将网页内容变暗。有关应用于 WebView 的深色主题示例,请参阅 GitHub 上的 WebView 演示。
最佳实践
以下部分提供了实现深色主题的最佳实践。
通知和微件
对于您在设备上显示但不直接控制的 UI 界面,请确保您使用的任何视图反映了宿主应用的主题。两个示例是通知和启动器微件。
通知
使用系统提供的通知模板,例如 MessagingStyle
。这意味着系统负责应用正确的视图样式。
微件和自定义通知视图
对于启动器微件,或者如果您的应用使用自定义通知内容视图,请在浅色和深色主题下测试内容。
常见的需要注意的陷阱包括:
- 假设背景颜色总是浅色。
- 硬编码文本颜色。
- 在使用默认文本颜色时设置硬编码的背景颜色。
- 使用静态颜色的可绘制图标。
在所有这些情况下,请使用适当的主题属性而不是硬编码的颜色。
启动画面
如果您的应用有自定义启动画面,您可能需要对其进行修改以反映选定的主题。
移除任何硬编码的颜色,例如通过编程设置为白色的背景颜色。而是使用 ?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; }