求助:如何通过SwitchPreferenceCompat动态将所有Fragment背景设为红色?
需求与问题
我想通过SwitchPreferenceCompat把应用内所有Fragment的背景色设为红色,但在编写监听代码和MainActivity相关逻辑时遇到了麻烦。我试过一些操作,但不太清楚怎么写正确的监听代码,也不知道怎么在MainActivity里合理运用。我不需要完整的解决方案,只想要方向上的指引。
相关代码
Preferences XML
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <PreferenceCategory android:title="Game Settings"> <SeekBarPreference android:defaultValue="10" android:key="pennyCount" android:max="20" android:summary="@string/starting_penny_count_new_game" android:title="@string/starting_penny_count" app:min="1" app:showSeekBarValue="true" /> <SwitchPreferenceCompat android:key="fastAI" android:summary="@string/fast_ai_summary" android:title="@string/fast_ai" /> </PreferenceCategory> <PreferenceCategory android:title="Theme Settings"> <DropDownPreference android:defaultValue="AppTheme" android:entries="@array/themes" android:entryValues="@array/theme_values" android:key="theme" android:title="@string/app_theme" app:useSimpleSummaryProvider="true" /> <ListPreference android:defaultValue="System" android:entries="@array/theme_modes" android:entryValues="@array/theme_mode_values" android:key="themeMode" android:title="@string/theme_mode" app:useSimpleSummaryProvider="true" /> </PreferenceCategory> <PreferenceCategory android:title="About the App"> <Preference android:key="credits" android:summary="@string/about_app_summary" android:title="@string/about_penny_drop" /> </PreferenceCategory> <SwitchPreferenceCompat android:defaultValue="false" android:key="switchRed" android:title="Turn Background Color Red" app:theme="@style/SwitchTheme"/> </PreferenceScreen>
MainActivity.kt
package dev.mfazio.pennydrop import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.text.style.BackgroundColorSpan import android.view.Menu import android.view.MenuItem import android.widget.Switch import androidx.appcompat.app.AppCompatDelegate import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.onNavDestinationSelected import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import androidx.preference.PreferenceManager import com.google.android.material.bottomnavigation.BottomNavigationView class MainActivity : AppCompatActivity() { private lateinit var navController: NavController override fun onCreate(savedInstanceState: Bundle?) { val prefs = PreferenceManager.getDefaultSharedPreferences(this) val themeId = when (prefs.getString("theme", "AppTheme")) { "Crew" -> R.style.Crew "FTD" -> R.style.FTD "GPG" -> R.style.GPG "Hazel" -> R.style.Hazel "Kotlin" -> R.style.Kotlin else -> R.style.AppTheme } setTheme(themeId) val nightMode = when (prefs.getString("themeMode", "")) { "Light" -> AppCompatDelegate.MODE_NIGHT_NO "Dark" -> AppCompatDelegate.MODE_NIGHT_YES else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM } AppCompatDelegate.setDefaultNightMode(nightMode) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navHostFragment = supportFragmentManager.findFragmentById(R.id.containerFragment) as NavHostFragment this.navController = navHostFragment.navController val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav) bottomNav.setupWithNavController(this.navController) val appBarConfiguration = AppBarConfiguration(bottomNav.menu) setupActionBarWithNavController(this.navController, appBarConfiguration) } override fun onCreateOptionsMenu(menu: Menu?): Boolean { super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.options, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean = if (this::navController.isInitialized) { item.onNavDestinationSelected(this.navController) || super.onOptionsItemSelected(item) } else false override fun onSupportNavigateUp(): Boolean = (this::navController.isInitialized && this.navController.navigateUp()) || super.onSupportNavigateUp() }
SettingsFragment.kt
package dev.mfazio.pennydrop.fragments import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatDelegate import androidx.navigation.fragment.findNavController import androidx.preference.* import dev.mfazio.pennydrop.R class SettingsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences( savedInstanceState: Bundle?, rootKey: String? ) { setPreferencesFromResource(R.xml.preferences, rootKey) val themePreference = findPreference<DropDownPreference?>("theme") val themeModePreference = findPreference<ListPreference?>("themeMode") val creditsPreference = findPreference<Preference?>("credits") val switchPreference = findPreference<SwitchPreferenceCompat>("switchRed") themePreference?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ -> activity?.recreate() true } themeModePreference?.setDefaultValue(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) themeModePreference?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> val nightMode = when (newValue?.toString()) { "Light" -> AppCompatDelegate.MODE_NIGHT_NO "Dark" -> AppCompatDelegate.MODE_NIGHT_YES else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM } AppCompatDelegate.setDefaultNightMode(nightMode) true } creditsPreference?.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ -> this.findNavController().navigate(R.id.aboutFragment) true } } }
Styles XML
<resources> <style name="AppTheme" parent="Theme.MaterialComponents.DayNight"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="colorSurface">@color/nightLightGray</item> </style> <style name="Kotlin" parent="AppTheme"> <item name="colorPrimary">@color/kotlinBlue</item> <item name="colorPrimaryDark">@color/kotlinPurple</item> <item name="colorAccent">@color/kotlinOrange</item> </style> <style name="Crew" parent="AppTheme"> <item name="colorPrimary">@color/crewBlue</item> <item name="colorPrimaryDark">@color/crewLightBlue</item> <item name="colorAccent">@color/crewGold</item> <item name="colorSurface">@color/crewBlue</item> </style> <style name="FTD" parent="AppTheme"> <item name="colorPrimary">@color/ftdGreen</item> <item name="colorPrimaryDark">@color/ftdGreen</item> <item name="colorAccent">@color/ftdBlue</item> </style> <style name="GPG" parent="AppTheme"> <item name="colorPrimary">@color/packGreen</item> <item name="colorPrimaryDark">@color/packGreen</item> <item name="colorAccent">@color/packGold</item> <item name="colorSurface">@color/packGreenDark</item> </style> <style name="Hazel" parent="AppTheme"> <item name="colorPrimary">@color/hazelBlue</item> <item name="colorPrimaryDark">@color/hazelDarkBlue</item> <item name="colorAccent">@color/hazelPink</item> </style> <style name="SwitchTheme" parent="AppTheme"> <item name="android:colorBackground">#FF0000</item> </style> </resources>
实现方向指引
- 给开关添加状态监听:在
SettingsFragment中找到switchRed实例,设置onPreferenceChangeListener。开关状态变化时,Preference会自动把布尔值保存到SharedPreferences,你只需要在回调里触发后续的背景更新逻辑(比如通知当前Fragment刷新,或者直接更新容器背景)。 - 统一Fragment背景设置逻辑:
- 推荐创建
BaseFragment作为所有Fragment的父类,在BaseFragment的onViewCreated或onResume方法中,读取SharedPreferences里的switchRed状态,然后给Fragment的根View设置对应的背景色(红色或默认色)。 - 也可以直接给MainActivity中的Fragment容器设置背景,但要注意Fragment布局是否有自己的背景覆盖容器。
- 推荐创建
- MainActivity配合更新:可以给
NavController添加addOnDestinationChangedListener,每次Fragment切换时,读取开关状态并更新当前Fragment的背景,或者更新容器背景。 - 避免不必要的Activity重建:不像主题切换,背景色更新不需要重建Activity,直接更新View的背景属性即可,这样更高效。
内容的提问来源于stack exchange,提问作者Andrew Amirzadeh
相关产品推荐
相关产品推荐

