Android深色模式适配指南

Android 深色模式(夜间模式)适配指南

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

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

0x01 DayNight 主题适配深色模式

将应用的主题背景(通常可在 res/values/styles.xml 中找到)设置为继承 DayNight 主题背景。

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

用到的资源和颜色需要在 -night 目录中重新配置一份。

在暗黑模式下,系统会优先从 -night 后缀的目录下找到对应的资源配置。

0x02 Force Dark 自动适配深色模式

如果您的应用采用浅色主题背景,则 Force Dark 会分析应用的每个视图,并在相应视图在屏幕上显示之前,自动应用深色主题背景。

Force Dark 应用需要满足以下三个条件

  • 使用系统及 AndroidX 提供的浅色主题背景(例如 Theme.Material.Light
  • 在其主题背景中设置 android:forceDarkAllowed="true"
  • 手机系统启用深色模式,Android 10 (API 级别 29)以上

如果您的应用使用深色主题(例如 Theme.Material),或者继承自 DayNight 主题背景,则系统不会应用 Force Dark。

在特定 View 上停用 Force Dark,可以通过 android:forceDarkAllowed 布局属性或 setForceDarkAllowed()

0x03 动态设置深色模式

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

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

  • 浅色 - MODE_NIGHT_NO
  • 深色 - MODE_NIGHT_YES
  • 由省电模式设置 - MODE_NIGHT_AUTO_BATTERY ( Android 9 或更低版本的设备上)
  • 系统默认 - MODE_NIGHT_FOLLOW_SYSTEM ( Android 10 (API 级别 29) 及更高版本上)

注意:从 AppCompat v1.1.0 开始,setDefaultNightMode() 会自动重新创建任何已启动的 Activity。

0x04 切换深色模式不重建 Activity

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

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

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

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

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

0x05 判断是否是深色模式

0x0501 判断当前 APP 是否是深色模式

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

1
2
3
4
5
val currentNightMode = context.resources.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
}

0x0502 判断当前手机系统是否是深色模式

如果要判断当前手机系统是否是深色模式,可以使用以下代码:

1
2
3
4
private fun isSystemNightMode(activity: Activity): Boolean {
val uiModeManager = activity.getSystemService(Context.UI_MODE_SERVICE)
return if (uiModeManager is UiModeManager) uiModeManager.nightMode == UiModeManager.MODE_NIGHT_YES else false
}

如何在 APP 内判断手机是否切换了系统深色模式?

前提是当前 APP 没有使用 android:configChanges="uiMode" 方式。
由于直接通过手机系统快捷设置切换深色模式时,会触发 activity 的 recreate()方法,导致 APP 的 activity 重建,但是在 activity 的 onPause()方法或者 APP 切换到后台时,获取到的深色模式状态已经是切换之后的了。所以,如果要判断 APP 使用过程中,系统是否切换深色模式,目前使用的方式是在进入 activity 时就记录一下当前的系统深色模式状态,然后,onStop 方法去检查系统的设置是否改变,并且把是否切换的值缓存在 APP 全局缓存(注意不能是 Activity 中)里。然后在 App 切换到前台的时候,再去获取缓存中的值,来判断上一次切换到后台时是否是因为系统切换了深色模式。

0x06 老项目深色模式适配指南

  1. compileSdkVersion 升级到 29 以上
  2. 使用 Force Dark 自动适配深色模式
  3. 针对有问题布局建立-night资源文件夹,配置对应的 color,drawable 和 layout 等
  4. APP 中的关键页面使用 DayNight 主题适配,以追求极致的 UI 体验

特别感谢

官网深色主题背景: https://developer.android.google.cn/guide/topics/ui/look-and-feel/darktheme?hl=zh-cn

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×