Android:切换暗黑主题时当前Fragment自动跳转为首个Fragment问题
问题场景
使用Bottom Navigation管理Fragment的Activity,通过选项菜单切换主题时,当前显示的Fragment会自动切换为首个Fragment,无法保持当前状态。当前主题切换代码如下:
override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.light_mode -> { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) sharedPrefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE) val editor = sharedPrefs.edit() editor.putBoolean(THEME_PREF_KEY, false) editor.apply() true } R.id.dark_mode -> { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) sharedPrefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE) val editor = sharedPrefs.edit() editor.putBoolean(THEME_PREF_KEY, true) editor.apply() true } R.id.log_out -> { logout() true } else -> super.onOptionsItemSelected(item) } }
问题原因
调用AppCompatDelegate.setDefaultNightMode()会触发Activity重启以应用新主题,而Activity重启后,Bottom Navigation会默认选中第一个菜单项,导致对应的Fragment被重新加载,覆盖了之前显示的Fragment。
解决方案
- 保存当前选中项:切换主题前,把Bottom Navigation当前选中的菜单项ID存入SharedPreferences。
- 恢复选中状态:在Activity的
onCreate方法中,读取保存的选中ID,设置Bottom Navigation的选中状态并切换到对应Fragment。 - 优化重复代码:提取SharedPreferences操作逻辑,避免冗余。
修改后的代码
1. 主题切换时保存当前选中项
// 定义保存选中项的Key private const val SELECTED_NAV_ITEM_KEY = "selected_nav_item" override fun onOptionsItemSelected(item: MenuItem): Boolean { val sharedPrefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE) val editor = sharedPrefs.edit() return when (item.itemId) { R.id.light_mode -> { // 保存当前选中的Bottom Navigation项 editor.putInt(SELECTED_NAV_ITEM_KEY, bottomNavigationView.selectedItemId) editor.putBoolean(THEME_PREF_KEY, false) editor.apply() AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) true } R.id.dark_mode -> { editor.putInt(SELECTED_NAV_ITEM_KEY, bottomNavigationView.selectedItemId) editor.putBoolean(THEME_PREF_KEY, true) editor.apply() AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) true } R.id.log_out -> { logout() true } else -> super.onOptionsItemSelected(item) } }
2. 在Activity onCreate中恢复选中状态
override fun onCreate(savedInstanceState: Bundle?) { // 先读取主题设置并应用 val sharedPrefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE) val isDarkMode = sharedPrefs.getBoolean(THEME_PREF_KEY, false) AppCompatDelegate.setDefaultNightMode(if (isDarkMode) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav) // 恢复之前选中的Bottom Navigation项 val selectedItemId = sharedPrefs.getInt(SELECTED_NAV_ITEM_KEY, R.id.first_fragment) // 默认第一个Fragment bottomNavigationView.selectedItemId = selectedItemId // 初始化Bottom Navigation的Fragment切换逻辑 bottomNavigationView.setOnItemSelectedListener { menuItem -> when (menuItem.itemId) { R.id.first_fragment -> { supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, FirstFragment()) .commit() true } R.id.second_fragment -> { supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, SecondFragment()) .commit() true } // 其他Fragment项... else -> false } } }
注意事项
- 确保
bottomNavigationView是Activity中对应的控件实例,ID与布局文件一致。 - 主题设置需在
super.onCreate(savedInstanceState)之前调用,保证主题在Activity创建时生效。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

