shortspider
shortspider

Reputation: 1055

Change Activity Theme From a Fragment

I have a settings PreferenceFragment that allows the user to select a theme. The user can select a dark or light theme. After selecting a theme the user presses the back button to return to the previous fragment. This called the containing activity's onCreate method where the theme is read and applied. However the theme is not applied correctly, Switching from Holo.Light to Holo.Dark changes the background colour, action bar etc but does not change the text resulting in faded, hard to read text. Any ideas what I am doing wrong? Everything I have read says that the theme should be applied in the onCreate method and that is what I am doing.

Thanks in advance for your help.

EDIT

As requested here is the relevant code.

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);
     }
}

The onCreate method applies the current theme to the activity by calling applySettings. The options menu allows for a SettingsFragment to be created.

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);
   }

 }

The SettingsFragment has one setting, Theme which can have one of two values, Dark or Light. The user picks one and then hits the back button. This causes the onCreate method of the MainActivity to be called, again applying the settings but not correctly.

Anyone? I feel like that once the theme is changed in the SettingsFragment and then the back button is pressed the theme should be applied to MainActivity but it is not. Most elements change but the text stays dark (going from Holo.Light to Holo.Dark).

Upvotes: 3

Views: 9016

Answers (3)

Lisa Wray
Lisa Wray

Reputation: 2272

I think I can help you with this. I spent a lot of time over the last few months working on the exact same thing for my app.

The above poster isn't exactly correct. You need to set the theme in onCreate() before views are instantiated -- before setContentView(). When super.onCreate() is called isn't important. I don't see setContentView() in your code above, so I'm wondering if you removed it?

However, if your activity is being themed correctly when you rotate (because it is destroyed and recreated on orientation change) then there's nothing wrong with how you're setting the theme. Instead, I'm inclined to think you're mistaken about onCreate() being called when you exit the SettingsFragment.

You can force your activity to recreate itself like this:

finish();
startActivity(getIntent());

Please first try setting a breakpoint in your activity's onCreate() method and confirm whether it's hit on exiting your fragment (I bet it's not.) Then try the code above.

Upvotes: 2

Phil H
Phil H

Reputation: 897

The problem here is that unless you recreate the activity the theme will not be applied. Themes are applied to an activity prior to setContentView method call in onCreate(). When you navigate back you are not re-entering through the onCreate() method but through onResume().

To work around this issue, changing a theme preference will mean having to clear the back stack, otherwise the theme will not be applied to the activities in the back stack. From a usability point of view this sort of setting should only be available through the top level activities of your app anyway.

Implement a ThemeChangeListener and add it to your activities. When the theme changes, call the ThemeChangeListener and call finish() on any open activities (apart from the page you are in). Then in onBack() manually recreate the top level activity the user navigated to the settings page from using the code Lisa supplied.

You can use intent extras/data to manage re-creating the parent activity with the data previously populated.

Upvotes: 0

Sadegh
Sadegh

Reputation: 2669

Call applySetting() before super.onCreate().

If it's not working neither, answer this: when you set your preferences to dark style and close your app completely, when you open your activity, does your style is fine? ( check this with both applySetting() before and after `super.onCreate() )

Upvotes: 0

Related Questions