A Blog to Write about Everything

0%

人升开发日志#15 | 06/16 夜间模式

收到多次需要夜间模式的反馈,就研究了一下要怎么实现~

本以为需要手动替换Theme,实际上Android已经提供了相应的功能。

实际使用之后才发现,Fragment能实现到和Activity在使用上分辨不出的效果。

依赖

首先是依赖,需要使用appcompat:(我这里用的androidx库,support库同理)

1
implementation 'androidx.appcompat:appcompat:1.1.0-beta01'


准备资源

  1. Activity的主题要继承自 DayNight 主题

    1
    2
    3
    4
    5
    6
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.DayNight">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    </style>
  2. 创建values-night文件夹,并在里面放置一份相应的colors.xml

    步骤:

    1. res文件夹右键 -> New -> New Resource Directory
    • Directory name 输入values-night

    • Resource type 输入values

    1. 将原本的colors.xml复制一份到values-night文件夹内。
  3. 调整夜间模式内的颜色值。


编程实现切换

需要注意的是,这里切换没有考虑到状态的保留。用的是finish+startActivity+动画效果。

一开始使用recreate方法,发现会卡顿一下,而且没有动画效果。

切换按钮的逻辑

判断模式的代码参考了:https://juejin.im/entry/586863f1ac502e006d6f1aa8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

//获取当前的模式,设置相反的模式,这里只使用了,夜间和非夜间模式
val currentMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
val editor = SharedPreferencesUtils.getStatusPreferencesInstance().edit()

if (currentMode != Configuration.UI_MODE_NIGHT_YES) {
//保存夜间模式状态,Application中可以根据这个值判断是否设置夜间模式
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
//ThemeConfig主题配置,这里只是保存了是否是夜间模式的boolean值
editor.putBoolean("isNightMode", true).apply()
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
editor.putBoolean("isNightMode", false).apply()
}

val intent = Intent(this, MainActivity::class.java)
finish()
overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
startActivity(intent)

自定义Application的相应逻辑

1
2
3
4
5
if (SharedPreferencesUtils.getStatusPreferencesInstance().getBoolean("isNightMode", false)) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}

难点

其实,夜间模式的实现并不困难。难的是:

  • 相应的夜间模式颜色配置
  • 切换实现流畅的动画效果
  • 切换实现保留状态
  • 切换后确保所有页面都是夜间模式

我这里是将夜间模式的按钮放在了主页的侧边栏,所以finish之后肯定是唯一一个activity,所以不用考虑残留页面的问题。

保留状态这一点也没有考虑,有需要的话可以参考一下https://juejin.im/entry/58eb498e0ce463005869dd3b

另外还有通过windowAnimation配合recreate的方法,但是实际测试好像动画不会生效。