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

Знам как да задам тема на цялото приложение в манифеста, но как да задам тема на цялото приложение програмно? Опитвам това: 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, да го промените и след това да го запишете обратно. Ако искате динамично да зададете темата за всички дейности, тогава мисля, че най-добрата идея е да създадете Template Activity, която задава темата си в onCreate и след това всички ваши други дейности да разширят този клас. - person Joseph Earl; 01.04.2011

Прекарах много време, за да накарам това да работи и сега моето приложение има избираеми светли и тъмни теми, които дори могат да се избират динамично, влизайки незабавно в игра, включително 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, grrrr! - 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);

}

//styles.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