如何在Android中通过Switch Button切换App为dark theme深色主题
Android 实现Switch切换深色主题方案
1. 基础主题适配配置
首先确认项目使用DayNight系列兼容主题,分别定义日夜间两套主题配置:
- 在
res/values/styles.xml中定义日间主题:
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar"> <item name="colorPrimary">@color/purple_500</item> <item name="colorPrimaryVariant">@color/purple_700</item> <item name="colorOnPrimary">@color/white</item> <item name="android:statusBarColor">?attr/colorPrimaryVariant</item> <!-- 其他自定义属性 --> </style>
- 新建
res/values-night/styles.xml定义深色主题:
<style name="AppTheme" parent="Theme.MaterialComponents.Dark.NoActionBar"> <item name="colorPrimary">@color/purple_200</item> <item name="colorPrimaryVariant">@color/purple_400</item> <item name="colorOnPrimary">@color/black</item> <item name="android:statusBarColor">?attr/colorPrimaryVariant</item> <!-- 其他深色模式下的自定义属性 --> </style>
所有需要适配主题的颜色,都需要分别在res/values/colors.xml和res/values-night/colors.xml中定义对应色值,不要在布局、代码中硬编码色值。
2. 持久化存储主题状态
通过SharedPreferences存储用户的主题选择,避免应用重启后设置丢失,可封装为工具类调用:
object ThemeHelper { private const val PREF_NAME = "theme_config" private const val KEY_DARK_MODE = "is_dark_mode" // 应用当前保存的主题 fun applySavedTheme(context: Context) { val darkModeEnabled = getDarkModeState(context) AppCompatDelegate.setDefaultNightMode( if (darkModeEnabled) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO ) } // 保存用户选择的主题状态 fun saveDarkModeState(context: Context, isDark: Boolean) { context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) .edit() .putBoolean(KEY_DARK_MODE, isDark) .apply() } // 读取已保存的主题状态,默认返回false(日间模式) fun getDarkModeState(context: Context): Boolean { return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) .getBoolean(KEY_DARK_MODE, false) } }
3. 绑定Switch控件交互逻辑
在放置Switch的Activity/Fragment中添加切换监听,注意主题应用方法要放在super.onCreate和setContentView之前调用:
override fun onCreate(savedInstanceState: Bundle?) { // 必须在super.onCreate之前调用,否则主题不生效 ThemeHelper.applySavedTheme(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_settings) val themeSwitch = findViewById<Switch>(R.id.switch_dark_theme) // 初始化Switch状态为已保存的主题状态 themeSwitch.isChecked = ThemeHelper.getDarkModeState(this) themeSwitch.setOnCheckedChangeListener { _, isChecked -> ThemeHelper.saveDarkModeState(this, isChecked) // 重建当前Activity让主题立刻生效 recreate() // 若需要全局所有已打开页面立刻生效,可发送广播通知栈内其他Activity也执行recreate } }
额外优化说明
- 所有Activity的
onCreate方法都要在最开头调用ThemeHelper.applySavedTheme(this),否则新打开页面的主题会不生效 - 如果不需要切换时的Activity重启闪烁效果,可在
recreate()后调用overridePendingTransition(0, 0)取消默认切换动画 - 若使用Jetpack Compose开发,只需要在主题Composable中根据存储的状态判断调用
darkColorScheme或lightColorScheme即可,不需要重建Activity
内容的提问来源于stack exchange,提问作者Sina Moradi
相关产品推荐
相关产品推荐

