Как изменить текущую тему во время выполнения на Android

Я создал функцию PreferenceActivity, которая позволяет пользователю выбирать тему, которую он хочет применить ко всему приложению.

Когда пользователь выбирает тему, этот код выполняется:

if (...) {
    getApplication().setTheme(R.style.BlackTheme);
} else {
    getApplication().setTheme(R.style.LightTheme);
}

Но, хотя я проверил с отладчиком, что этот код выполняется, я не вижу никаких изменений в пользовательском интерфейсе.

Темы определены в res/values/styles.xml, а Eclipse не показывает никаких ошибок.

<resources>
    <style name="LightTheme" parent="@android:style/Theme.Light">
    </style>

    <style name="BlackTheme" parent="@android:style/Theme.Black">
    </style>    
</resources>

Любая идея о том, что может произойти и как это исправить? Должен ли я звонить setTheme в любой специальной точке кода? Мое приложение состоит из нескольких действий, если это помогает.

Ответ 1

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

Для справки проверьте это:

http://www.anddev.org/applying_a_theme_to_your_application-t817.html

Изменить (скопировано с этого форума):

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Call setTheme before creation of any(!) View.
     setTheme(android.R.style.Theme_Dark);

    // ...
    setContentView(R.layout.main);
}

Ответ 2

Если вы хотите изменить тему уже существующего действия, вызовите recreate() после setTheme().

Примечание: не вызывайте воссоздание, если вы меняете тему в onCreate(), чтобы избежать бесконечного цикла.

Ответ 3

recreate() (как упоминалось TPReal) перезапустит текущую активность, но предыдущие действия будут по-прежнему находиться в обратном стеке, и тема не будет применяться к ним.

Итак, еще одно решение этой проблемы - полностью воссоздать стек задач, например:

    TaskStackBuilder.create(getActivity())
            .addNextIntent(new Intent(getActivity(), MainActivity.class))
            .addNextIntent(getActivity().getIntent())
            .startActivities();

EDIT:

Просто поместите код выше после того, как вы измените тему в пользовательском интерфейсе или в другом месте. Все ваши действия должны иметь метод setTheme(), называемый до onCreate(), возможно, в некоторых родительских действиях. Это также обычный подход для сохранения темы, выбранной в SharedPreferences, прочитайте ее, а затем установите с помощью метода setTheme().

Ответ 4

У меня такая же проблема, но я нашел решение.

public class EditTextSmartPhoneActivity extends Activity implements DialogInterface.OnClickListener
{
    public final static int CREATE_DIALOG  = -1;
    public final static int THEME_HOLO_LIGHT  = 0;
    public final static int THEME_BLACK  = 1;

    int position;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        position = getIntent().getIntExtra("position", -1);

        switch(position)
        {
        case CREATE_DIALOG:
            createDialog();
            break;
        case THEME_HOLO_LIGHT:
            setTheme(android.R.style.Theme_Holo_Light);
            break;
        case THEME_BLACK:
            setTheme(android.R.style.Theme_Black);
            break;
        default:
        }

        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

    }

    private void createDialog()
    {
        /** Options for user to select*/
        String choose[] = {"Theme_Holo_Light","Theme_Black"};

        AlertDialog.Builder b = new AlertDialog.Builder(this);

        /** Setting a title for the window */
        b.setTitle("Choose your Application Theme");

        /** Setting items to the alert dialog */
        b.setSingleChoiceItems(choose, 0, null);

        /** Setting a positive button and its listener */
        b.setPositiveButton("OK",this);

        /** Setting a positive button and its listener */
        b.setNegativeButton("Cancel", null);

        /** Creating the alert dialog window using the builder class */
        AlertDialog d = b.create();

        /** show dialog*/
        d.show();
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        // TODO Auto-generated method stub
        AlertDialog alert = (AlertDialog)dialog;
        int position = alert.getListView().getCheckedItemPosition();

        finish();
        Intent intent = new Intent(this, EditTextSmartPhoneActivity.class);
        intent.putExtra("position", position);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

Ответ 5

Мы должны задать тему перед вызовом метода 'super.onCreate()' и 'setContentView().

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

Ответ 6

У меня была аналогичная проблема, и я решил таким образом.

@Override
public void onCreate(Bundle savedInstanceState) {

    if (getIntent().hasExtra("bundle") && savedInstanceState==null){
        savedInstanceState = getIntent().getExtras().getBundle("bundle");
    }

    //add code for theme

    switch(theme)
    {
    case LIGHT:
        setTheme(R.style.LightTheme);
        break;
    case BLACK:
        setTheme(R.style.BlackTheme);
        break;

    default:
    }
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //code

}

этот код предназначен для воссоздания спада активности и изменения темы. Вы должны написать свой собственный onSaveInstanceState (Bundle outState); Из API-11 вы можете использовать метод recreate() вместо

Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();

Ответ 7

Это то, что я создал для Material Design. Пусть это поможет вам.

Посмотрите MultipleThemeMaterialDesign

Ответ 8

Я знаю, что я опаздываю, но я бы хотел опубликовать решение здесь: Проверьте полный исходный код здесь. Это код, который я использовал при изменении темы, используя настройки.

SharedPreferences pref = PreferenceManager
        .getDefaultSharedPreferences(this);
String themeName = pref.getString("prefSyncFrequency3", "Theme1");
if (themeName.equals("Africa")) {
    setTheme(R.style.AppTheme);
} else if (themeName.equals("Colorful Beach")) {
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show();
    setTheme(R.style.beach);
} else if (themeName.equals("Abstract")) {
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show();
    setTheme(R.style.abstract2);
} else if (themeName.equals("Default")) {
    setTheme(R.style.defaulttheme);
}

Ответ 9

Вместо

getApplication().setTheme(R.style.BlackTheme);

использование

setTheme(R.style.BlackTheme);

Мой код: в методе onCreate():

super.onCreate(savedInstanceState);

if(someExpression) {
    setTheme(R.style.OneTheme);
} else {
    setTheme(R.style.AnotherTheme);
}

setContentView(R.layout.activity_some_layout);

Где-то (например, при нажатии кнопки):

YourActivity.this.recreate();

Вам нужно воссоздать активность, иначе - изменения не произойдет

Ответ 10

Этот способ работает для меня:

  @Override
protected void onCreate(Bundle savedInstanceState) {
    setTheme(GApplication.getInstance().getTheme());
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);
}

Затем вы хотите изменить новую тему:

GApplication.getInstance().setTheme(R.style.LightTheme);
recreate();

Ответ 11

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

Ответ 12

Вызов SetContentView (Resource.Layout.Main) после setTheme().

Ответ 13

Это не повлияло на меня:

public void changeTheme(int newTheme) {
    setTheme(newTheme);
    recreate();
}

Но это сработало:

int theme = R.style.default;

protected void onCreate(Bundle savedInstanceState) {
    setTheme(this.theme);
    super.onCreate(savedInstanceState);
}

public void changeTheme(int newTheme) {
    this.theme = newTheme;
    recreate();
}