我的 ListPreference 在运行时没有改变 App Theme
My ListPreference is not changing App Theme during runtime
每当我在 ListPreference
中选择一个项目来更改我的应用程序的主题时,如何让我的 Activity
重新创建自己并保持特定的主题?出于某种原因,无论选择 ListPreference
中的哪个项目,我的应用程序都停留在浅色主题上。我不确定我在这里做错了什么。
styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light"/>
<style name="MyDarkSettingsTheme" parent="Theme.AppCompat"/>
<style name="MyLightSettingsTheme" parent="Theme.AppCompat.Light"/>
</resources>
Activity
class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
// Declaring initial value for applying appropriate Theme
private var mCurrentValue: Boolean = true // True is the default value
override fun onCreate(savedInstanceState: Bundle?) {
// Checking which Theme should be used. IMPORTANT: applying Themes MUST called BEFORE super.onCreate() and setContentView!!!
val mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
mCurrentValue = mSharedPreferences.getBoolean("light", true)
if (mCurrentValue) setTheme(R.style.MyLightSettingsTheme)
else setTheme(R.style.MyDarkSettingsTheme)
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
// In order to recreate Activity, we must check the value here. Because, when we come back from another Activity, the onCreate isn't called again.
override fun onStart() {
super.onStart()
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
val mFrameLayout = findViewById<FrameLayout>(R.id.settings)
val mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
val mNewValue = mSharedPreferences.getBoolean("light", true)
// If value differs from previous Theme, recreate Activity
if (mCurrentValue != mNewValue) recreate()
// if (mNewValue) {
// mFrameLayout.setBackgroundColor(Color.WHITE)
// }
// else {
// mFrameLayout.setBackgroundColor(Color.BLACK)
// }
// ... do other stuff here
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
override fun onDestroy() {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
//...
super.onDestroy()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
when (key) {
"list_theme" -> {
if (sharedPreferences.getString(key, "light") == "light") {
setTheme(R.style.MyLightSettingsTheme)
recreate()
}
else if (sharedPreferences.getString(key, "dark") == "dark") {
setTheme(R.style.MyDarkSettingsTheme)
recreate()
}
}
}
}
}
1) Activity 已打开
2) ListPreference 点击
3) 已选择深色偏好
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_settings -> {
val intentSettings = Intent(this, SettingsActivity ::class.java)
startActivity(intentSettings)
true
}
else ->
super.onOptionsItemSelected(item)
}
}
}
首先,您需要在 styles.xml
文件中添加更多 colors/themes。
示例:
<!-- Base Light application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<!--Dark Theme Default-->
<style name="AppThemeDark" parent="Theme.AppCompat">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
在我的 Base Application
class 中,我添加了这 3 个方法。我的应用程序有 3 个主题,如果您有更多主题,您可以相应地编辑代码。
@Override
public void onCreate() {
super.onCreate();
PreferenceManager.setDefaultValues(this, R.xml.pref_main, false);
Context context = this;
context.setTheme(getUserTheme());
mInstance = this;
res = getResources();
shared = PreferenceManager.getDefaultSharedPreferences(context);
}
public static int getTheme(Context context, int light, int dark, int amoled) {
String darkTheme = context.getString(R.string.dark_mode_theme);
String amoledTheme = context.getString(R.string.amoled_mode_theme);
shared = PreferenceManager.getDefaultSharedPreferences(context);
String theme = shared.getString(Constants.PREFERENCE_THEME, darkTheme);
//Able to access these values outside the class!
if (theme.equals(darkTheme)) {
return dark;
} else if (theme.equals(amoledTheme)) {
return amoled;
} else {
return light;
}
}
private int getUserTheme() {
return getTheme(this, R.style.AppTheme, R.style.AppThemeDark, R.style.AppThemeAMOLED);
}
如果您没有扩展 Application
的 class,请创建它,然后通过将此行放在 <Application>
标记中将其添加到 AndroidMainfest
android:name="App"
我还在Base Activity Class
中添加了以下方法。我所有的活动都扩展了这个 class。如果您的应用只有一个 activity,这与您的相关性较低。
protected abstract int getAppTheme(); //has to be implemented in anything that extends this class
protected void setAppTheme(int id) {
super.setTheme(id);
themeId = id;
}
protected void onResume() {
super.onResume()
if (themeId !== getAppTheme())
{
recreate();
}
}
更改主题后,您需要重新创建 activity 以激活更改。
recreate();
不幸的是,您不能从静态方法中调用它。我还建议在 onCreate 中检查主题,如果当前主题与用户选择的主题不匹配,则更改主题然后调用 recreate();
.
接下来,在扩展基础 activity class 的常规 activity 中,我添加了这个。确保在任何地方都保持相同的顺序。如果不这样做,主题将不匹配。
public int getAppTheme() {
return App.getTheme(this, R.style.AppTheme, R.style.AppThemeDark, R.style.AppThemeAMOLED);
}
每当我在 ListPreference
中选择一个项目来更改我的应用程序的主题时,如何让我的 Activity
重新创建自己并保持特定的主题?出于某种原因,无论选择 ListPreference
中的哪个项目,我的应用程序都停留在浅色主题上。我不确定我在这里做错了什么。
styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light"/>
<style name="MyDarkSettingsTheme" parent="Theme.AppCompat"/>
<style name="MyLightSettingsTheme" parent="Theme.AppCompat.Light"/>
</resources>
Activity
class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
// Declaring initial value for applying appropriate Theme
private var mCurrentValue: Boolean = true // True is the default value
override fun onCreate(savedInstanceState: Bundle?) {
// Checking which Theme should be used. IMPORTANT: applying Themes MUST called BEFORE super.onCreate() and setContentView!!!
val mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
mCurrentValue = mSharedPreferences.getBoolean("light", true)
if (mCurrentValue) setTheme(R.style.MyLightSettingsTheme)
else setTheme(R.style.MyDarkSettingsTheme)
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
// In order to recreate Activity, we must check the value here. Because, when we come back from another Activity, the onCreate isn't called again.
override fun onStart() {
super.onStart()
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
val mFrameLayout = findViewById<FrameLayout>(R.id.settings)
val mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
val mNewValue = mSharedPreferences.getBoolean("light", true)
// If value differs from previous Theme, recreate Activity
if (mCurrentValue != mNewValue) recreate()
// if (mNewValue) {
// mFrameLayout.setBackgroundColor(Color.WHITE)
// }
// else {
// mFrameLayout.setBackgroundColor(Color.BLACK)
// }
// ... do other stuff here
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
override fun onDestroy() {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
//...
super.onDestroy()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
when (key) {
"list_theme" -> {
if (sharedPreferences.getString(key, "light") == "light") {
setTheme(R.style.MyLightSettingsTheme)
recreate()
}
else if (sharedPreferences.getString(key, "dark") == "dark") {
setTheme(R.style.MyDarkSettingsTheme)
recreate()
}
}
}
}
}
1) Activity 已打开
2) ListPreference 点击
3) 已选择深色偏好
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_settings -> {
val intentSettings = Intent(this, SettingsActivity ::class.java)
startActivity(intentSettings)
true
}
else ->
super.onOptionsItemSelected(item)
}
}
}
首先,您需要在 styles.xml
文件中添加更多 colors/themes。
示例:
<!-- Base Light application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<!--Dark Theme Default-->
<style name="AppThemeDark" parent="Theme.AppCompat">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
在我的 Base Application
class 中,我添加了这 3 个方法。我的应用程序有 3 个主题,如果您有更多主题,您可以相应地编辑代码。
@Override
public void onCreate() {
super.onCreate();
PreferenceManager.setDefaultValues(this, R.xml.pref_main, false);
Context context = this;
context.setTheme(getUserTheme());
mInstance = this;
res = getResources();
shared = PreferenceManager.getDefaultSharedPreferences(context);
}
public static int getTheme(Context context, int light, int dark, int amoled) {
String darkTheme = context.getString(R.string.dark_mode_theme);
String amoledTheme = context.getString(R.string.amoled_mode_theme);
shared = PreferenceManager.getDefaultSharedPreferences(context);
String theme = shared.getString(Constants.PREFERENCE_THEME, darkTheme);
//Able to access these values outside the class!
if (theme.equals(darkTheme)) {
return dark;
} else if (theme.equals(amoledTheme)) {
return amoled;
} else {
return light;
}
}
private int getUserTheme() {
return getTheme(this, R.style.AppTheme, R.style.AppThemeDark, R.style.AppThemeAMOLED);
}
如果您没有扩展 Application
的 class,请创建它,然后通过将此行放在 <Application>
标记中将其添加到 AndroidMainfest
android:name="App"
我还在Base Activity Class
中添加了以下方法。我所有的活动都扩展了这个 class。如果您的应用只有一个 activity,这与您的相关性较低。
protected abstract int getAppTheme(); //has to be implemented in anything that extends this class
protected void setAppTheme(int id) {
super.setTheme(id);
themeId = id;
}
protected void onResume() {
super.onResume()
if (themeId !== getAppTheme())
{
recreate();
}
}
更改主题后,您需要重新创建 activity 以激活更改。
recreate();
不幸的是,您不能从静态方法中调用它。我还建议在 onCreate 中检查主题,如果当前主题与用户选择的主题不匹配,则更改主题然后调用 recreate();
.
接下来,在扩展基础 activity class 的常规 activity 中,我添加了这个。确保在任何地方都保持相同的顺序。如果不这样做,主题将不匹配。
public int getAppTheme() {
return App.getTheme(this, R.style.AppTheme, R.style.AppThemeDark, R.style.AppThemeAMOLED);
}