Android 6.0以后系统提供了AppCompatDelegate用来实现夜间模式和日间模式的切换,AppCompatDelegate中存在以下几种模式:
AppCompatDelegate.MODE_NIGHT_YES:设置夜间模式
AppCompatDelegate.MODE_NIGHT_NO:设置日间模式
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM:跟随系统设置决定是否设置夜间模式
AppCompatDelegate.MODE_NIGHT_AUTO:根据当前时间自动切换模式
实现夜间模式需要配置两套资源文件而且资源文件的命名要完全一致,后缀带-night的目录对应夜间模式,比如values对应日间模式,values-night对应夜间模式,系统会根据当前的模式自动加载对应的资源文件。
| 日间模式 | 夜间模式 |
| values | values-night |
| drawable | drawable-night |
| drawable-xhdpi | drawable-night-xhdpi |
| mipmap-mdpi | mipmap-night-mdpi |
| mipmap-hdpi | mipmap-night-hdpi |
| mipmap-xhdpi | mipmap-night-xhdpi |
| mipmap-xxhdpi | mipmap-night-xxhdpi |
| mipmap-xxxhdpi | mipmap-night-xxxhdpi |
首先设置应用主题为DayNight模式,如Theme.AppCompat.DayNight.DarkActionBar或者Theme.MaterialComponents.DayNight.DarkActionBar,如下:
- @color/purple_500
- @color/purple_700
- @color/white
- @color/teal_200
- @color/teal_700
- @color/black
- ?attr/colorPrimaryVariant
AndroidManifest配置application的android:theme:
顺便说一下,现在在Android Studio 4.0以上新建的project已经默认主题样式为Theme.MaterialComponents.DayNight.DarkActionBar,同时已经配置了日间和夜间两套主题文件theme.xml。
配置颜色src/main/res目录下新建values-night目录,在该目录下新建colors.xml,然后配置同一个颜色值在values/colors.xml和values-night/colors.xml、也就是日间模式和夜间模式下对应的取值,注意颜色值的命名要完全一样。
values/colors.xml取值如下:
#000000 #FFFFFF #FFFFFF
values-night/colors.xml取值如下:
配置图片#FFFFFF #000000 #000000
src/main/res目录下新建mipmap-night-xhdpi目录,在mipmap-night-xhdpi和mipmap-xhdpi目录分别配置夜间和日间模式的两套图片,注意两张图片的命名要完全一样。以ic_pic为例,项目结构如下:
使用在布局文件中使用配置好的颜色和图片:
其中shape_btn_bg如下:
在代码中使用:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initMode()
modeTv.setonClickListener {
switchMode()
}
}
private fun initMode() {
when (AppCompatDelegate.getDefaultNightMode()) {
AppCompatDelegate.MODE_NIGHT_NO -> {
modeTv.text = "日间模式"
}
AppCompatDelegate.MODE_NIGHT_YES -> {
modeTv.text = "夜间模式"
}
else -> {
modeTv.text = "日间模式"
}
}
}
//切换夜间模式
private fun switchMode() {
when (AppCompatDelegate.getDefaultNightMode()) {
AppCompatDelegate.MODE_NIGHT_NO -> { //当前为日间模式
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) //切换为夜间模式
}
AppCompatDelegate.MODE_NIGHT_YES -> { //当前为夜间模式
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) //切换为日间间模式
}
else -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) //切换为夜间模式
}
}
recreate() //需要调用该方法才能生效
}
}
最后看一下效果:
源码地址



