Изменить тему действия из фрагмента

У меня есть настройки 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 имеет одну настройку, Тема, которая может иметь одно из двух значений: Темная или Светлая. Пользователь выбирает один и затем нажимает кнопку «Назад». Это вызывает вызов метода onCreate из MainActivity, снова применяя настройки, но не правильно.

Кто угодно? Мне кажется, что после изменения темы в SettingsFragment и нажатия кнопки «Назад» тема должна быть применена к MainActivity, но это не так. Большинство элементов меняются, но текст остается темным (переход от Holo.Light к Holo.Dark).


person shortspider    schedule 15.07.2013    source источник
comment
Более подробная информация о том, что вы пробовали до сих пор/код, поможет. Вы явно определили свой текст для изменения. Как ты это сделал?   -  person Jade Byfield    schedule 15.07.2013
comment
Я предполагаю, что в какой-то момент вы заканчиваете это действие (и вы можете использовать это PreferenceFragment в PreferenceActivity вместо обычного)? Так же проблема с текстом тоже для ActionBar или только для просмотров(если таковые используются)?   -  person user    schedule 23.07.2013
comment
@Luksprog Проблема с текстом - это просто просмотры. В настоящее время у меня есть только одно действие, и я просто заменяю части макета разными фрагментами (например, мой SettingsFragment). Итак, чтобы ответить на ваш вопрос, нет, я не заканчиваю работу, так как на самом деле это просто для хранения моих фрагментов. Метод onCreate вызывается при выходе из SettingsFragment, поэтому тема применяется так, как если бы активность была воссоздана. Верно? Это неправильный подход к предпочтениям?   -  person shortspider    schedule 23.07.2013
comment
Убедитесь, что ваши представления используют правильную ссылку Context при их создании (которая будет контекстом действия, а не чем-то вроде getApplicationContext()). Я должен признать, что я не понимаю, как вызывается onCreate() после того, как вы нажмете назад, который должен просто вытолкнуть SettingsFragment (вы сами это называете). Предпочтения должны быть реализованы в их собственной деятельности (PreferenceActivity).   -  person user    schedule 23.07.2013
comment
Убедитесь, что вы не определяете цвет текста с помощью R.color.white или чего-то подобного.   -  person tbruyelle    schedule 23.07.2013
comment
@Luksprog спасибо за отзыв, я посмотрю и посмотрю, имеет ли значение использование действия настроек вместе с фрагментом, я начинаю думать, что это может иметь больше смысла и с точки зрения пользователя. Просто для справки, я использую getActivity, а не getApplicationContext, поэтому я не думаю, что это все. Говорит ли Google где-нибудь, что PreferenceActivity нужно/следует использовать? Насколько я понимаю, большинство вещей нужно делать с помощью Fragments?   -  person shortspider    schedule 23.07.2013
comment
@tbruyelle Я использую стандартные темы Holo.Light и Holo.Dark, у меня вообще нет определенных цветов или стилей.   -  person shortspider    schedule 23.07.2013


Ответы (3)


Я думаю, что могу помочь вам с этим. За последние несколько месяцев я потратил много времени, работая над тем же самым для своего приложения.

Вышеприведенный плакат не совсем правильный. Вам нужно установить тему в onCreate() перед созданием экземпляров представлений -- перед setContentView(). Когда вызывается super.onCreate(), не важно. Я не вижу setContentView() в вашем коде выше, поэтому мне интересно, удалили ли вы его?

Тем не менее, если ваша деятельность правильно оформлена при повороте (поскольку она уничтожается и воссоздается при изменении ориентации), то нет ничего плохого в том, как вы устанавливаете тему. Вместо этого я склонен думать, что вы ошибаетесь в том, что onCreate() вызывается при выходе из SettingsFragment.

Вы можете заставить свою деятельность воссоздать себя следующим образом:

finish();
startActivity(getIntent());

Пожалуйста, сначала попробуйте установить точку останова в методе onCreate() вашей активности и подтвердите, сработала ли она при выходе из вашего фрагмента (держу пари, что это не так). Затем попробуйте код выше.

person Lisa Wray    schedule 23.07.2013
comment
Я добавил, где я вызываю setContentView в моем коде выше. Если я назову завершение и запущу новое действие, потеряю ли я свой задний стек? - person shortspider; 24.07.2013
comment
Вы правы, onCreate() не вызывается при нажатии кнопки «Назад». - person shortspider; 26.07.2013
comment
Вы можете использовать метод recreate() класса Activity для воссоздания вместо finish() и startActivity(getIntent()); - person Adnan Khan; 13.07.2017

Вызовите applySetting() перед super.onCreate().

Если это тоже не работает, ответьте на этот вопрос: когда вы устанавливаете свои предпочтения в темном стиле и полностью закрываете свое приложение, когда вы открываете свою активность, ваш стиль в порядке? (проверьте это как с applySetting() до, так и после `super.onCreate())

person Sadegh    schedule 23.07.2013
comment
на данный момент, если вы перезапустите приложение или повернете приложение, тема будет применена правильно, я попытаюсь вызвать applySettings() перед super.onCreate() и посмотреть, что произойдет. - person shortspider; 23.07.2013

Проблема здесь в том, что если вы не воссоздадите активность, тема не будет применена. Темы применяются к действию до вызова метода setContentView в onCreate(). Когда вы возвращаетесь назад, вы повторно входите не через метод onCreate(), а через onResume().

Чтобы обойти эту проблему, изменение предпочтения темы будет означать необходимость очистки заднего стека, иначе тема не будет применяться к действиям в заднем стеке. В любом случае, с точки зрения удобства использования, этот вид настройки должен быть доступен только через действия верхнего уровня вашего приложения.

Реализуйте ThemeChangeListener и добавьте его в свои действия. Когда тема изменится, вызовите ThemeChangeListener и вызовите finish() для любых открытых действий (кроме страницы, на которой вы находитесь). Затем в onBack() вручную воссоздайте действие верхнего уровня, когда пользователь перешел на страницу настроек, используя код, предоставленный Лизой.

Вы можете использовать дополнительные данные/данные намерения для управления повторным созданием родительского действия с ранее заполненными данными.

person Phil H    schedule 25.07.2013