web-dev-qa-db-fra.com

Comment changer de thème (mode nuit) sans redémarrer l'activité?

J'ai créé quelques applications qui prennent en charge plusieurs thèmes, mais j'ai toujours dû redémarrer l'application lorsque l'utilisateur change de thème, car setTheme() doit être appelé avant setContentView().

J'étais d'accord avec ça, jusqu'à ce que je découvre cette application. Il peut facilement basculer entre deux thèmes, et avec des transitions/animations aussi!

enter image description here

Veuillez me donner quelques conseils sur la façon dont cela a été mis en œuvre (et les animations aussi). Merci!

38
user1032613

La réponse de @Alexander Hanssen a fondamentalement répondu à cela ... Je ne sais pas pourquoi elle n'a pas été acceptée ... Peut-être à cause de finish ()/startActivity (). J'ai voté pour et j'ai essayé de commenter mais je ne peux pas ...

Quoi qu'il en soit, je ferais exactement ce qu'il a décrit en termes de styles.

<style name="AppThemeLight" parent="Theme.AppCompat.Light">
    <!-- Customize your theme here. -->
    <item name="Android:windowAnimationStyle">@style/WindowAnimationTransition</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
    <!-- Customize your theme here. -->
    <item name="Android:windowAnimationStyle">@style/WindowAnimationTransition</item>
</style>
<!-- This will set the fade in animation on all your activities by default -->
<style name="WindowAnimationTransition">
    <item name="Android:windowEnterAnimation">@Android:anim/fade_in</item>
    <item name="Android:windowExitAnimation">@Android:anim/fade_out</item>
</style>

Mais au lieu de terminer/commencer avec une nouvelle intention:

Intent intent = new Intent(this, <yourclass>.class);
startActivity(intent);
finish();

Je ferais:

@Override
protected void onCreate(Bundle savedInstanceState) {

    // MUST do this before super call or setContentView(...)
    // pick which theme DAY or NIGHT from settings
    setTheme(someSettings.get(PREFFERED_THEME) ? R.style.AppThemeLight : R.style.AppThemeDark);

    super.onCreate(savedInstanceState);
}

// Somewhere in your activity where the button switches the theme
btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {

        // decide which theme to use DAY or NIGHT and save it
        someSettings.save(PREFFERED_THEME, isDay());

        Activity.this.recreate();
    }
});

L'effet est comme indiqué dans la vidéo ...

46
GKA

La transition/animation rend le changement de thème transparent lorsque vous redémarrez l'activité, et cela peut être fait en ajoutant les éléments "Android: windowanimationStyle" à vos thèmes, puis en référençant un style dans lequel vous spécifiez comment l'animation doit s'animer lorsqu'elle entre et sort. Notez que cela fait que l'animation s'applique à toutes les activités avec ce thème.

<style name="AppThemeLight" parent="Theme.AppCompat.Light">
    <!-- Customize your theme here. -->
    <item name="Android:windowAnimationStyle">@style/WindowAnimationTransition</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
    <!-- Customize your theme here. -->
    <item name="Android:windowAnimationStyle">@style/WindowAnimationTransition</item>
</style>
<!-- This will set the fade in animation on all your activities by default -->
<style name="WindowAnimationTransition">
    <item name="Android:windowEnterAnimation">@Android:anim/fade_in</item>
    <item name="Android:windowExitAnimation">@Android:anim/fade_out</item>
</style>

Ensuite, lorsque vous souhaitez changer de thème, vous pouvez le faire en cliquant sur un bouton:

AppSettings settings = AppSettings.getInstance(this);
settings.set(AppSettings.Key.USE_DARK_THEME,
!settings.getBoolean(AppSettings.Key.USE_DARK_THEME));
Intent intent = new Intent(this, <yourclass>.class);
startActivity(intent);
finish();

Ensuite, dans votre méthode onCreate, utilisez la fonction setTheme() pour appliquer le thème actuellement défini dans AppSettings comme ceci:

AppSettings settings = AppSettings.getInstance(this);
setTheme(settings.getBoolean(AppSettings.Key.USE_DARK_THEME) ? R.style.AppThemeDark : R.style.AppThemeLight);
super.onCreate(savedInstanceState);
setContentView(<yourlayouthere>);

Consultez ce Gist pour référence: https://Gist.github.com/alphamu/f2469c28e17b24114fe5

14
Alexander Hanssen

Rien ne vous empêche d'appeler setTheme() puis setContentView(). Vous aurez juste besoin de restructurer un peu votre application afin que, si vous changez de thème, vous deviez réinitialiser toutes les variables membres que vous pourriez avoir qui contiennent des références à des objets View.

1
David Wasser