Как установить тему для всего приложения в коде, но не в манифесте?

Я знаю, как установить тему для всего приложения в манифесте, но как установить тему для всего приложения программно? Я пытаюсь сделать это: getApplicationContext.setTheme(R.style.mytheme ), но это не работает.

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


person Judy    schedule 01.04.2011    source источник
comment
Вы пытаетесь установить тему всех действий только одним фрагментом кода (т.е. используя getApplicationContext())??   -  person 100rabh    schedule 12.05.2011
comment
Я думаю, вам следует прокомментировать Джозефа Эрла. Его ответы могут объяснить, что мы не можем не установить тему всех действий с помощью getApplicationContext().   -  person Judy    schedule 12.05.2011
comment
Так это был твой вопрос. В следующий раз постарайтесь сделать заголовок поста ближе к вашему вопросу. Удачи.   -  person 100rabh    schedule 12.05.2011


Ответы (6)


Вы не можете применить его ко всему приложению из Java, если только вы не используете код Java для изменения файла манифеста. Другие действия, к которым вы хотите применить тему, могут даже не выполняться, так как же Android применит к ним тему? И после выхода и возврата в вашу программу все изменения будут потеряны, и вам нужно будет снова применить тему.

getApplicationContext действительно возвращает контекст приложения, но только потому, что метод принимает Context, не означает, что передача ему ApplicationContext внезапно заставит его повлиять на все приложение. На самом деле это не так и будет работать так, как если бы вы использовали обычный контекст.

Скорее, важность разных контекстов заключается в том, что они существуют в течение разного времени: контекст действия создается и уничтожается вместе с действием, а контекст приложения создается при запуске первого компонента приложения и уничтожается при уничтожении последнего компонента.

person Joseph Earl    schedule 01.04.2011
comment
Я понял. Но как изменить файл манифеста с помощью java-кода? - person Judy; 01.04.2011
comment
Не уверен, что сможете, но вам придется прочитать файл как XML, изменить его, а затем сохранить обратно. Если вы хотите динамически установить тему для всех действий, я думаю, что лучшей идеей было создать действие шаблона, которое устанавливает свою тему в onCreate, а затем все остальные действия расширяют этот класс. - person Joseph Earl; 01.04.2011

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

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--The base theme ensures nothing is shown until the first activity. All activities and fragmenst must-->
    <!--set a them in onCreate or in AndroidManifext or they wil crash because of no title.-->
    <!--Using Theme.Holo.NoActionBar suppresses the ActionBar initially so Icon doesn't show until new theme is set.-->
    <style name="MyAppThemeInitial" parent="@android:style/Theme.Holo">
        <!--<item name="android:windowBackground">@color/initial_background_grey</item>-->
        <!--<item name="android:actionBarStyle">@style/MyActionBar</item>-->
        <item name="android:windowDisablePreview">true</item>

    </style>
    <style name="MyAppThemeDark" parent="@android:style/Theme.Holo">
        <item name="android:windowBackground">@color/black</item>
    </style>
    <style name="MyAppThemeLight" parent="android:Theme.Holo.Light">
    <item name="android:windowBackground">@color/white</item>
    </style>


<!--&lt;!&ndash;This is so that only the icon is showing in the intial theme&ndash;&gt;-->
    <!--&lt;!&ndash; ActionBar styles &ndash;&gt;-->
    <!--<style name="MyActionBar" parent="@android:style/Widget.Holo.ActionBar">-->
        <!--<item name="android:background">@android:color/transparent</item>-->
        <!--<item name="android:titleTextStyle">@style/MyActionBarTextAppearance</item>-->
    <!--</style>-->

    <!--<style name="MyActionBarTextAppearance">-->
        <!--<item name="android:textColor">@android:color/transparent</item>-->
    <!--</style>-->

</resources> 

Ключевым элементом здесь является

<item name="android:windowDisablePreview">true</item>

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

Чтобы иметь возможность перезапускать приложение динамически, я проверяю, было ли приложение запущено/перезапущено таким образом.

SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
boolean useThemeLight = sp.getBoolean("useThemeLight", false);
//Since this Activity can also be started by the Theme Toggle in the Action bar we need to see if
//there is a TOGGLE_THEME extra which only it uses
Intent curIntent = this.getIntent();
if (curIntent.getExtras() != null && curIntent.getExtras().containsKey(TOGGLE_THEME)) {
    if(curIntent.getStringExtra(TOGGLE_THEME).equals("Dark")){
        this.setTheme(R.style.MyAppThemeDark);
        CurrentTheme = "Dark";
    }else{
        this.setTheme(R.style.MyAppThemeLight);
        CurrentTheme = "Light";
    }
    activityThemeToggleActive = true;
} else {
    if (useThemeLight) {
        this.setTheme(R.style.MyAppThemeLight);
        CurrentTheme = "Light";
    } else {
        this.setTheme(R.style.MyAppThemeDark);
        CurrentTheme = "Dark";
    }
}

В настройках я делаю это.

SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
boolean useThemeLight = sp.getBoolean("useThemeLight", false);
if (useThemeLight) {
    this.setTheme(R.style.MyAppThemeLight);
} else {
    this.setTheme(R.style.MyAppThemeDark);
}

Надеюсь, это поможет вам начать. С уважением, Джон.

person jcddcjjcd    schedule 29.01.2014
comment
ты спас мне жизнь с <item name="android:windowDisablePreview">true</item> - person Tin Nguyen; 04.11.2019
comment
Да, согласен... <item name="android:windowDisablePreview">true</item> очень полезно... У меня была вспышка светлой темы перед установкой темной темы, потому что светлая тема была в манифесте... теперь я могу установить эту фиктивную тему в манифесте, чтобы нет вспышки неправильной темы до того, как нужная активируется. - person drmrbrewer; 17.01.2020

Вызовите setTheme перед super.onCreate(), как показано ниже.

  public void onCreate(Bundle icicle) {
           if(Utility.isThemed)
             setTheme(R.style.Mytheme);
           super.onCreate(icicle);
    .....
    .....
}
person 100rabh    schedule 01.04.2011
comment
Зачем вызывать его перед 'super.onCreate()'. Вызовите его до того, как setContentView будет в порядке, верно? - person Judy; 01.04.2011
comment
@100rabh Где? Применение или активность? - person Anderson; 30.11.2012
comment
@Judy: Бывают случаи, когда super.onCreate() может создавать экземпляры некоторых представлений, поэтому вызов setTheme() перед super.onCreate() — хорошая идея. - person LarsH; 17.08.2015
comment
Спасибо!! Я делал после, и когда я повернул экран, он потерял тему и вернулся к теме, определенной в манифесте. - person SammyT; 25.04.2018

В setTheme в документации написано:

Обратите внимание, что это следует вызывать до того, как будут созданы экземпляры каких-либо представлений в контексте (например, перед вызовом setContentView(View) или inflate(int, ViewGroup)).

Вы позаботились об этом?

person rajath    schedule 01.04.2011
comment
Да, я позаботился об этом. У меня есть вызов getApplicationContext.setTheme(R.style.mytheme) перед setContentView(view). Но если вызвать setTheme(R.style.mytheme), тема просто применяется к активности. Интересно, можно ли установить тему для всего приложения, написав код? - person Judy; 01.04.2011
comment
Я не думаю, что для этого существует API (но не уверен), но вы можете получить все свои действия из общего базового действия, внутри которого вы вызываете указанную выше функцию setTheme. - person rajath; 01.04.2011
comment
Спасибо. Провел весь день, задаваясь вопросом, почему панель действий не использует мою тему - устанавливала тему после setContentView, грррр! - person HGPB; 26.08.2012

Вы можете создать BaseActivity. Измените свой стиль в этом действии. Все ваши действия наследуются от этого действия.

person Amri    schedule 04.09.2018

Я использую пользовательскую активность для всех действий в моем приложении.

Затем я проверяю значение предпочтения в onCreate моей унаследованной активности, например.

public class MyCustomActivity extends Activity {

protected void onCreate(Bundle savedInstanceState) {
        SharedPreferences prefs = PreferenceManager
                .getDefaultSharedPreferences(this);
        if(prefs.getBoolean("use_light_theme",false)==true)
        {
            setTheme(R.style.AppThemeLight);
        }
        super.onCreate(savedInstanceState);

}

//стили.xml

    <!-- Base application theme. -->
    <style name="AppTheme" parent="android:Theme.Holo">
        <!-- Customize your theme here. -->
    </style>
    <style name="AppThemeLight" parent="android:Theme.Light">
        <!-- Customize your theme here. -->
    </style>
person Justin Mecham    schedule 13.08.2015