从一个Fragment更改Activity主题

3
我有一个设置的PreferenceFragment,允许用户选择主题。用户可以选择深色或浅色主题。选择主题后,用户按返回按钮返回到前一个片段。这将调用包含活动的onCreate方法,其中读取并应用主题。但是,主题没有正确应用,从Holo.Light切换到Holo.Dark会更改背景颜色、操作栏等,但不会更改文本,导致文字模糊、难以阅读。我做错了什么?我所读的所有内容都说主题应在onCreate方法中应用,这就是我正在做的事情。
提前感谢您的帮助。
编辑
如请求所示,下面是相关代码。
public class MainActivity extends Activity {

     private ActionBarDrawerToggle mSlideMenuToggle;
     private boolean isDarkTheme;
     private static final String InitializedKey = "initialized";

     @Override
 protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
          applySettings();
          setContentView(R.layout.activity_main);
       }

     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
          if (mSlideMenuToggle.onOptionsItemSelected(item)) {
               return true;
          } else if (item.getItemId() == R.id.menu_settings) {
               getFragmentManager().beginTransaction()
                        .replace(R.id.content_frame, new SettingsFragment())
                        .addToBackStack(null)
                        .commit();
               return true;
          } else {
               return super.onOptionsItemSelected(item);
          }
     }

     private void applySettings() {
          isDarkTheme = PreferenceManager.getDefaultSharedPreferences(this).getString(SettingsFragment.ThemeSetting, null).equals("1");
          if (isDarkTheme) {
               setTheme(android.R.style.Theme_Holo);
          } else {
               setTheme(android.R.style.Theme_Holo_Light);
     }
}

onCreate方法通过调用applySettings将当前主题应用于活动。选项菜单允许创建SettingsFragment

public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {

   public static final String ThemeSetting = "isDarkTheme";

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       addPreferencesFromResource(R.xml.preferences);
   }

   @Override
   public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
       if (key.equals(ThemeSetting)) {
           String[] themes = getResources().getStringArray(R.array.isDarkThemeStrings);
           findPreference(key).setSummary(sharedPreferences.getString(key, "").equals("0") ? themes[0] : themes[1]);
       }
   }

   @Override
   public void onResume() {
       super.onResume();
       PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(this);
   }

   @Override
   public void onPause() {
       super.onPause();
       PreferenceManager.getDefaultSharedPreferences(getActivity()).unregisterOnSharedPreferenceChangeListener(this);
   }

 }
SettingsFragment 只有一个设置,主题可以有两个值:Dark 或 Light。用户选择一个值,然后按返回按钮。这将导致 MainActivityonCreate 方法被调用,再次应用设置但是不正确。
有人能帮忙解决吗?我感觉一旦在 SettingsFragment 中更改了主题并按下返回按钮后,主题应该应用于 MainActivity,但实际上却没有。大多数元素会改变,但文本仍保持为暗色(从 Holo.Light 到 Holo.Dark)。

提供更多关于你已经尝试过的内容或代码的细节会有所帮助。你是否明确定义了要更改的文本?你是如何做到的? - Jade Byfield
我假设在某个时候你会完成这项活动(并且你可能想在PreferenceActivity中使用那个PreferenceFragment而不是普通的一个)?此外,文本的问题也适用于ActionBar还是只适用于视图(如果您使用任何视图)? - user
@Luksprog 文本问题只是视图。目前我只有一个活动,并用不同的片段(即我的“SettingsFragment”)替换布局的部分。所以回答你的问题,我没有完成这个活动,因为它只是用来容纳我的片段。然而,当离开“SettingsFragment”时,“onCreate”方法会被调用,因此主题会被应用,就好像活动已经重新创建了一样。对吗?这是偏好设置的错误方法吗? - shortspider
@Luksprog 感谢您的反馈,我会看看是否使用首选项活动和片段一起使用会有所不同,我开始认为从用户的角度来看这可能更有意义。只是作为一个 FYI,我正在使用 getActivity 而不是 getApplicationContext,所以我不认为那是问题所在。Google 是否说过需要/应该使用 PreferenceActivity?我的理解是大多数事情都应该用 Fragments 来完成? - shortspider
@tbruyelle 我正在使用标准的Holo.Light和Holo.Dark主题,我没有定义任何颜色或样式。 - shortspider
显示剩余2条评论
3个回答

2
我认为我可以帮助你。在过去的几个月里,我花了很多时间为我的应用程序做完全相同的事情。
上面的海报并不完全正确。您需要在实例化视图之前-在`setContentView()`之前-在`onCreate()`中设置主题。调用`super.onCreate()`并不重要。我在您上面的代码中没有看到`setContentView()`,所以我想知道您是否将其删除了?
但是,如果您的活动在旋转时被正确地主题化(因为它在方向更改时被销毁并重新创建),则您设置主题的方式没有问题。相反,我倾向于认为您对退出SettingsFragment时调用`onCreate()`感到困惑。
您可以像这样强制重新创建活动:
finish();
startActivity(getIntent());

请先尝试在您的活动的 onCreate() 方法中设置断点,并确认在退出片段时是否已触发(我打赌没有)。然后尝试上面的代码。

我在上面的代码中添加了调用setContentView的位置。如果我调用finish并启动一个新的活动,那么我会失去我的后退堆栈吗? - shortspider
你是正确的,当返回按钮被按下时,onCreate()方法不会被调用。 - shortspider
你可以使用Activity类的recreate()方法进行重建,而不是使用finish()和startActivity(getIntent())。 - Adnan Khan

0

在调用 super.onCreate() 之前调用 applySetting()

如果还不起作用,请回答这个问题:当您将偏好设置设置为暗色样式并完全关闭应用程序后,当您打开活动时,您的样式是否正常?(使用 applySetting() 在 `super.onCreate()` 之前和之后都检查一下)


目前,如果您重新启动应用程序或旋转应用程序,则主题将正确应用。我将尝试在super.onCreate()之前调用applySettings(),看看会发生什么。 - shortspider

0
问题在于,除非重新创建活动,否则主题将不会应用。主题是在onCreate()方法中的setContentView()方法调用之前应用于活动的。当您返回时,您不是通过onCreate()方法重新进入,而是通过onResume()方法。
为了解决这个问题,改变主题偏好意味着必须清除后退堆栈,否则主题将不会应用于后退堆栈中的活动。从可用性的角度来看,这种设置只应该通过您应用程序的顶级活动提供。
实现一个ThemeChangeListener并将其添加到您的活动中。当主题更改时,调用ThemeChangeListener并在任何打开的活动上调用finish()(除了您所在的页面)。然后在onBack()中使用Lisa提供的代码手动重新创建用户从设置页面导航到的顶级活动。
您可以使用意图额外数据来管理使用先前填充的数据重新创建父活动。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接