164 votes

Comment changer le thème actuel au moment de l'exécution dans Android ?

J'ai créé une PreferenceActivity qui permet à l'utilisateur de choisir le thème qu'il souhaite appliquer à l'ensemble de l'application.

Lorsque l'utilisateur sélectionne un thème, ce code est exécuté :

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

Mais, bien que j'aie vérifié avec le débogueur que le code s'exécute, je ne vois aucun changement dans l'interface utilisateur.

Les thèmes sont définis dans res/values/styles.xml et Eclipse ne montre pas d'erreur.

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

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

Une idée de ce qui pourrait se passer et de la manière de le réparer ? Dois-je appeler setTheme à un endroit particulier du code ? Mon application se compose de plusieurs activités, si cela peut vous aider.

0 votes

97voto

Pentium10 Points 68884

J'aimerais aussi voir la méthode qui consiste à définir une fois toutes les activités. Mais pour autant que je sache, vous devez définir chaque activité avant d'afficher des vues.

Pour référence, vérifiez ceci :

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

Edit (copié de ce forum) :

    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);
    }

Modifier
Si vous appelez setTheme après super.onCreate(savedInstanceState); votre activité est recréée mais si vous appelez setTheme avant super.onCreate(savedInstanceState); votre thème se fixe et s'active ne se recrée plus

  protected void onCreate(Bundle savedInstanceState) {
     setTheme(android.R.style.Theme_Dark);
     super.onCreate(savedInstanceState);

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

3 votes

Cela fonctionne, mais les changements ne sont pas appliqués tant que vous ne passez pas d'une activité à une autre...

22 votes

Veuillez fournir une réponse autonome afin que, si le lien disparaît, les gens puissent toujours avoir accès à votre réponse.

1 votes

@TashPemhiwa et autres upvoters de ce commentaire : aurait-il été difficile de modifier la réponse vous-même ?

67voto

TPReal Points 119

Si vous voulez changer le thème d'une activité déjà existante, appelez [recreate()](http://developer.android.com/reference/android/app/Activity.html#recreate()) après setTheme() .

Note : n'appelez pas recreate si vous changez de thème dans le fichier onCreate() pour éviter une boucle infinie.

3 votes

Cette réponse serait plus utile si elle citait des preuves ou un raisonnement expliquant pourquoi il est nécessaire de faire appel à l'aide de l'UE. recreate() même si la documentation ( developer.Android.com/reference/Android/content/ ) dit simplement setTheme() avant que les vues ne soient instanciées. Voulez-vous dire qu'il faut appeler recreate() seulement si les vues ont déjà été instanciées ?

3 votes

En particulier, si vous appelez setTheme() dans votre onCreate() avant d'appeler super.onCreate() ou setContentView(), (1) vous devrez vérifier pour éviter une boucle infinie où vous continuez à recréer ; et (2) qu'avez-vous gagné de toute façon ?

0 votes

C'est très utile. Je savais déjà comment définir le thème avant le chargement, mais le changer immédiatement est nécessaire pour une expérience utilisateur raisonnable. recreate est juste la chose dont j'avais besoin.

16voto

Unknown Points 1283

J'ai eu le même problème mais j'ai trouvé la solution.

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);
    }
}

3 votes

C'est pour permettre à l'utilisateur de sélectionner un thème au moment de l'exécution, sans avoir à le définir dans le manifeste.

0 votes

Ça marche. Je l'ai couplé avec une configuration de préférences partagées pour que le changement de thème soit persistant.

2 votes

Est l'appel à super.onCreate() après setTheme() également essentiel pour que cela fonctionne ? J'avais l'impression qu'il suffisait d'appeler setTheme() avant d'appeler setContentView()

11voto

Lalit Points 130

Nous devons définir le thème avant d'appeler super.onCreate() ". y setContentView() méthode.

Regarde ça lien pour appliquer un nouveau thème à l'ensemble de l'application au moment de l'exécution.

2 votes

Apparemment, cela signifie "avant d'appeler super.onCreate() et setContentView()." BTW J'ai rétrogradé cette réponse plus tôt parce qu'elle semblait incorrecte ; maintenant, je comprends ce qui a été signifié, et je vois de la valeur dans cette réponse (même si elle n'a pas été exprimée clairement). Je ne peux pas changer mon vote, cependant, à moins que la réponse ne soit modifiée. Si cela se produit, veuillez m'en informer afin que je puisse changer mon vote.

1 votes

@LarsH ha ha ha Aucun problème.

2 votes

Je l'ai édité et enlevé le downvote.

11voto

Francesco Ditrani Points 106

J'ai eu un problème similaire et je l'ai résolu de cette façon

@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

}

ce code est pour recréer l'activité en sauvegardant le Bundle et en changeant le thème. Vous devez écrire votre propre code onSaveInstanceState(Bundle outState) ; Depuis l'API-11, vous pouvez utiliser la méthode recreate() à la place.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X