简介
Android 10(API级别29)版本开始,Google提供了深色模式。
官方介绍详见:https://developer.android.com/guide/topics/ui/look-and-feel/darktheme
深色模式的优势
- 更好的用户体验
- 减少耗电量
- 为弱视以及对强光敏感的用户提高可视性
深色模式的启用
- 设置 -> 显示 -> 深色模式
- 下拉通知栏中开启
- Pixel 手机开启省电模式时会自动激活
适配
通过应用主题设配
要直接支持深色主题背景,可以将应用的主题设置为
<style name="AppTheme" parent="Theme.AppCompat.DayNight">
或者
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
DayNight主题会将应用主要的主题背景与系统控制的深色模式相关联,跟随系统的深色模式开启关闭而变化。
Theme.AppCompat.DayNight
res\values\values.xml
res\values-night-v8\values-night-v8.xml
以上截图可以看出,DayNight主题就是在values和values-night中分别定义了浅色和深色的主题,如果应用主题是直接继承DayNight主题,就不需要重复地声明对应的night
主题资源了。
验证如下
主题继承DayNight,没有设置颜色(包括背景颜色及字体颜色),开启深色模式,系统会强制将背景及字体设置为深色模式,例如:
tips:控件如果设置了背景颜色或者字体颜色,不管系统是否已经开启深色模式,均显示为代码里设置的颜色。
应用内资源文件适配
常见的需要设置的资源有anim
、drawable
、layout
、values
等,对于这些资源,可以使用限定符来提供一些备用资源;例如深色模式可以使用限定符-night
来表示在深色模式中使用的资源,如下图:
tips:-night文件夹里只放置在深色模式中需要改变的资源,若浅色主题与深色主题使用的资源一样,则不需要在-night中新增;只在-night文件夹定义的资源而普通模式文件夹内没有的资源,能编译通过但是运行会崩溃。
网络图片适配
适配网络图片可以通过判断当前是否是应用深色主题,加载显示不同的图片。代码如下:
/**
* 判断当前是否是深色模式
* @param mContext 上下文
* @return true:深色,false:浅色
*/
public static boolean isNightMode(Context mContext){
return (mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
}
Configuration.uiMode有三种Night的模式
- UI_MODE_NIGHT_NO 表示当前使用的是
notnight
模式资源 - UI_MODE_NIGHT_YES 表示当前使用的是
night
模式资源 - UI_MODE_NIGHT_UNDEFINED 表示当前没有设置模式
直接设置使用深色模式
应用内可以直接调用AppCompatDelegate.setDefaultNightMode(),设置使用深色模式;共有以下几种场景:
- MODE_NIGHT_AUTO_BATTERY 低电量模式自动开启深色模式
- MODE_NIGHT_FOLLOW_SYSTEM 跟随系统开启和关闭深色模式(默认)
- MODE_NIGHT_NO 强制使用
notnight
资源,表示非深色模式 - MODE_NIGHT_YES 强制使用
night
资源 - MODE_NIGHT_UNSPECIFIED 配合 setLocalNightMode(int) 使用,表示由Activity通过AppCompactActivity.getDelegate()来单独设置页面的深色模式,不设置全局模式
深色模式设置可以从三个层级设置,分别是系统层、Applcation层以及Activity层;底层的设置会覆盖上层的设置。
-
系统层:是指在系统设置中开启深色模式
-
Applcation层:通过调用AppCompatDelegate.setDefaultNightMode()设置深色模式
static { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); }
-
Activity层:通过调用getDelegate().setLocalNightMode()设置当前页面的深色模式。
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setDefaultNightMode源码如下
public static void setDefaultNightMode(@NightMode int mode) {
if (DEBUG