黑暗的主题

Android Q提供了一个新的Dark主题,适用于Android系统UI和设备上运行的应用程序。

黑暗主题有很多好处:

  • 可以大幅减少用电量(取决于设备的屏幕技术)。
  • 提高低视力用户和对强光敏感的用户的可视性。
  • 使任何人都可以在光线不足的环境中使用设备。

在Android Q中,有三种方法可以启用Dark主题:

  • 新的系统设置(设置 - >显示 - >主题)允许用户启用黑暗主题。
  • 新的“快速设置”磁贴允许用户从通知托盘中快速切换主题(一旦启用)。
  • 在Pixel设备上,Battery Saver模式还可以同时启用Dark主题。其他OEM可能支持也可能不支持此行为。

 

在您的应用中支持Dark主题

 

为了支持Dark主题,您必须将应用程序的主题(通常位于 res/values/styles.xml)中设置为从DayNight主题继承:

 

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

 

您还可以使用 MaterialComponents的暗主题

 

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

 

这将应用程序的主题与系统控制的夜间模式标记联系起来,并为应用程序提供默认的Dark主题(启用时)。

 

主题和风格

 

您的主题和样式应避免使用硬编码颜色或旨在在浅色主题下使用的图标。您应该使用主题属性(首选)或夜间限定资源。

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

  • ?android:attr/textColorPrimary这是一种通用文本颜色。它在Light主题中接近黑色,在Dark主题上接近白色。它包含一个禁用状态。
  • ?attr/colorControlNormal通用图标颜色。它包含一个禁用状态。

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

 

在应用程序中更改主题

 

您可能希望允许用户在应用运行时更改应用的主题。您的应用可以让用户在主题之间进行选择。

在运行Android 9或更早版本的设备上运行时,推荐的主题选项为:

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

在Android Q上运行时,建议的选项不同,以允许用户覆盖系统默认值:

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

请注意,如果用户选择Light,则Battery Saver不会更改该设置。

每个选项都直接映射到其中一种AppCompat.DayNight模式:

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

注意:AppCompatv1.1.0-alpha05开始,setDefaultNightMode()不会自动重新创建任何已启动的活动。

 

强迫黑暗

 

Android Q提供Force Dark,这是开发人员在没有明确设置主题的情况下快速实现Dark主题的功能,DayNight如上所述。

Force Dark分析以光为主题的应用程序的每个视图,并在绘制到屏幕之前自动应用黑暗主题。一些开发人员使用Force Dark和本机实现的混合来减少实现Dark主题所需的时间。

应用必须通过设置android:forceDarkAllowed="true"应用主题来选择加入强黑。此属性设置在所有系统和AndroidX提供的轻量级主题上,例如Theme.Material.Light。当您使用Force Dark时,您应该确保彻底测试您的应用并根据需要排除视图。

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

 

禁用视图上的强制暗

 

可以使用android:forceDarkAllowed 布局属性或使用特定视图控制强制暗setForceDarkAllowed()

 

最佳实践

通知和小部件

 

对于您在设备上显示但未直接控制的UI表面,确保您使用的任何视图都反映主机应用程序的主题非常重要。两个很好的例子是通知和启动器小部件。

 

通知

 

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

 

窗口小部件和自定义通知视图

 

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

需要注意的常见陷阱:

  • 假设背景颜色总是很亮
  • 硬编码文本颜色
  • 使用默认文本颜色时设置硬编码背景颜色
  • 使用可绘制的图标,这是一种静态颜色

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

 

启动屏幕

 

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

删除任何硬编码颜色,例如任何背景颜色指向可能是白色。请改用?android:attr/colorBackground主题属性。

请注意,以黑暗为主题的android:windowBackgrounddrawable仅适用于Android Q.

 

配置更改

 

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

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

应用程序可以通过声明每个Activity可以处理uiMode 配置更改来处理Dark主题本身的实现:

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