Android Q 推出了深色模式,其实 Android 9 就有了,部分厂商小米,三星就在系统 Android 9 加入了深色模式的开关。
Android 提供了一套夜间模式主题,继承 Theme.MaterialComponents.DayNight.NoActionBar
主题即可。
然后在 res 文件夹创建 values-night
将深色模式的 color.xml 拷贝过来,系统在深色模式下会自动识别该目录下的 color 信息。当然,除了 color 之外的资源也是一样的。
同理 drawable
同样可以创建一个 drawable-night
来区别不同的资源。
判断深色模式
系统有几个 mask 值:
// 深色
public static final int UI_MODE_NIGHT_YES = 0x20;
// 浅色
public static final int UI_MODE_NIGHT_NO = 0x10;
// 判断是否是深色
context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
// 全局设置夜间模式
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
// 在 App 内部切换主题的时候重新创建 Activity 以应用
recreate()
初次进入 App 的时候,如果需要指定 Dark Mode,在你的 Application 中初始化:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
自定义处理
系统在切换深色/浅色模式时,会在 Actvity/Fragment 中回调
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
if(dark){
//
}else{
//
}
}
我们只要在这个回调填写 ui 深色变换的逻辑即可。
__注意: Activity 必须注册 android:configChanges="uiMode" 才能收到
onConfigurationChanged的回调
:
<activity
android:name=".ui.main.home.HomeActivity"
android:configChanges="uiMode">
基于这些基础,可以沉淀抽象出一套通用的 dake mode 库
一个额外发现
在应用了 Theme.MaterialComponents.DayNight
之后,同时系统切到了深色模式,很多页面的背景变成了全黑,拖动列表 item 还会有残影,在 twitter,知乎,即刻,华为商店,都看到过这种残影效果,之前在酷安看到一个图片中带黑色的局部,拖动图片,图片上的黑色局部也有那种残影效果,推测是利用屏幕的某种特性造成了这种视觉效果。之前我还以为是即刻和知乎自己自定义的这种动画效果。
不过也带来一个额外的问题-(App内部代码层面关闭了深色模式,但是系统的深色模式还开着时,这些页面依然是黑色的)。
这是因为 App 的 value 资源是按系统的深色模式来加载,只要系统的深色模式开着,不管 App 内部是否关闭了深色模式,总是走 value-night
的资源。最后的妥协是放弃在 App 内部自定义切换主题,这样最简单也省去了很多麻烦,(解决 bug 的最好办法,就是砍掉出 bug 的功能。逃😄2333333333333333333333333