我在我的应用程序中实际上有这个功能,此外,我允许用户在运行时更改主题。由于从偏好设置中读取值需要一些时间,因此我通过全局可访问函数获取一个主题ID,该函数保存了缓存值。
正如已经指出的那样 - 使用此指南创建一些Android主题:
(http://developer.android.com/guide/topics/ui/themes.html)。你的
styles.xml
文件中将至少有两个
<style>
项目。例如:
<style name="Theme.App.Light" parent="@style/Theme.Light">...</style>
<style name="Theme.App.Dark" parent="@style/Theme">...</style>
现在,您需要将这些样式之一应用到您的活动中。我将在活动
的onCreate
方法中执行此操作,在任何其他调用之前:
setTheme(MyApplication.getThemeId());
getThemeId
是一个返回缓存主题 ID 的方法:
public static int getThemeId()
{
return themeId;
}
该字段正在被另一种方法更新:
public static void reloadTheme()
{
themeSetting = PreferenceManager.getDefaultSharedPreferences(context).getString("defaultTheme", "0");
if(themeSetting.equals("0"))
themeId = R.style.Theme_Light;
else
themeId = R.style.Theme_Dark;
}
每当偏好设置改变时(以及在启动时),就会调用这两个方法。这两个方法位于MyApplication
类中,该类扩展了Application
。偏好更改监听器在此帖子末尾描述,并驻留在主活动类中。
最后一个非常重要的事情是 - 主题在活动启动时应用。假设您只能在偏好设置屏幕中更改主题,并且只有一种从一个(主要)活动进入该屏幕的方式,则退出偏好设置屏幕后,该活动不会重新启动 - 仍然使用旧主题。这是解决此问题的方法(重新启动主要活动):
@Override
protected void onResume() {
super.onResume();
if(schduledRestart)
{
schduledRestart = false;
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
scheduledRestart
是一个布尔变量,最初设置为 false。当主题被此监听器更改时,它将设置为 true,并更新之前提到的缓存主题 ID:
private class ThemeListener implements OnSharedPreferenceChangeListener{
@Override
public void onSharedPreferenceChanged(SharedPreferences spref, String key) {
if(key.equals("defaultTheme") && !spref.getString(key, "0").equals(MyApplication.getThemeSetting()))
{
MyApplication.reloadTheme();
schduledRestart = true;
}
}
sp = PreferenceManager.getDefaultSharedPreferences(this);
listener = new ThemeListener();
sp.registerOnSharedPreferenceChangeListener(listener);
记得持有监听器对象的引用,否则它会被垃圾回收(并且将停止工作)。
getApplication().setTheme(myThemeId)
,则getApplicationInfo().theme
不会更新... 所以是的,你的方法是正确的。 - vaultrecreate
(https://developer.android.com/reference/android/app/Activity.html#recreate%28%29)。 - BlueMonkMN