web-dev-qa-db-fra.com

Comment modifier réellement par programmation les couleurs primaire et d'accent dans Android Lollipop?

Tout d'abord, cette question pose une question très similaire. Cependant, ma question a une différence subtile.

Ce que j'aimerais savoir, c'est s'il est possible de modifier par programme l'attribut colorPrimary d'un thème en un arbitraire couleur?

Ainsi, par exemple, nous avons:

<style name="AppTheme" parent="Android:Theme.Material.Light">
    <item name="Android:colorPrimary">#ff0000</item>
    <item name="Android:colorAccent">#ff0000</item>
</style>

Au moment de l'exécution, l'utilisateur décide qu'il souhaite utiliser #ccffff en tant que couleur primaire. Bien sûr, je ne peux pas créer de thèmes pour toutes les couleurs possibles.

Cela ne me dérange pas si je dois faire des choses hacky, comme s'appuyer sur les internes privés d'Android, tant que cela fonctionne avec le SDK public.

Mon objectif est d’avoir éventuellement les variables ActionBar et comme un CheckBox pour utiliser cette couleur primaire.

147
nhaarman

Les thèmes sont immuables, vous ne pouvez pas.

171
Chris Banes

Je lis les commentaires sur l'application Contacts et comment elle utilise un thème pour chaque contact.

Probablement, l'application Contacts a des thèmes prédéfinis (pour chaque couleur primaire de matériau à partir d'ici: http://www.google.com/design/spec/style/color.html ).

Vous pouvez appliquer un thème avant une méthode setContentView à l'intérieur de la méthode onCreate.

Ensuite, l'application Contacts peut appliquer un thème de manière aléatoire à chaque utilisateur.

Cette méthode est:

setTheme(R.style.MyRandomTheme);

Mais cette méthode pose un problème. Par exemple, elle peut changer la couleur de la barre d’outils, la couleur de l’effet de défilement, la couleur de l’ondulation, etc., mais elle ne peut pas changer la couleur de la barre d’état ni celle de la barre de navigation (si vous souhaitez également la modifier).

Ensuite, pour résoudre ce problème, vous pouvez utiliser la méthode avant et:

if (Build.VERSION.SDK_INT >= 21) {
        getWindow().setNavigationBarColor(getResources().getColor(R.color.md_red_500));
        getWindow().setStatusBarColor(getResources().getColor(R.color.md_red_700));
    }

Ces deux méthodes changent la couleur de navigation et la barre d'état. N'oubliez pas que si vous définissez votre barre de navigation translucide, vous ne pouvez pas changer sa couleur.

Cela devrait être le code final:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setTheme(R.style.MyRandomTheme);
    if (Build.VERSION.SDK_INT >= 21) {
        getWindow().setNavigationBarColor(getResources().getColor(R.color.myrandomcolor1));
        getWindow().setStatusBarColor(getResources().getColor(R.color.myrandomcolor2));
    }
    setContentView(R.layout.activity_main);

}

Vous pouvez utiliser un commutateur et générer un nombre aléatoire pour utiliser des thèmes aléatoires ou, comme dans l'application Contacts, chaque contact est probablement associé à un numéro prédéfini.

Un échantillon de thème:

<style name="MyRandomTheme" parent="Theme.AppCompat.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/myrandomcolor1</item>
    <item name="colorPrimaryDark">@color/myrandomcolor2</item>
    <item name="Android:navigationBarColor">@color/myrandomcolor1</item>
</style>

Désolé pour mon anglais.

62

Vous pouvez utiliser Theme.applyStyle pour modifier votre thème à l'exécution en lui appliquant un autre style.

Disons que vous avez ces définitions de style:

<style name="DefaultTheme" parent="Theme.AppCompat.Light">
    <item name="colorPrimary">@color/md_Lime_500</item>
    <item name="colorPrimaryDark">@color/md_Lime_700</item>
    <item name="colorAccent">@color/md_amber_A400</item>
</style>

<style name="OverlayPrimaryColorRed">
    <item name="colorPrimary">@color/md_red_500</item>
    <item name="colorPrimaryDark">@color/md_red_700</item>
</style>

<style name="OverlayPrimaryColorGreen">
    <item name="colorPrimary">@color/md_green_500</item>
    <item name="colorPrimaryDark">@color/md_green_700</item>
</style>

<style name="OverlayPrimaryColorBlue">
    <item name="colorPrimary">@color/md_blue_500</item>
    <item name="colorPrimaryDark">@color/md_blue_700</item>
</style>

Vous pouvez maintenant patcher votre thème au moment de l’exécution de la manière suivante:

getTheme().applyStyle(R.style.OverlayPrimaryColorGreen, true);

La méthode applyStyle doit être appelée avant que la présentation ne soit gonflée! Donc, à moins de charger manuellement la vue, vous devez appliquer des styles au thème avant d'appeler setContentView dans votre activité.

Bien sûr, cela ne peut pas être utilisé pour spécifier une couleur arbitraire, c'est-à-dire une sur 16 millions (2563) couleurs. Mais si vous écrivez un petit programme qui génère les définitions de style et le code Java pour vous, vous obtiendrez quelque chose comme l'un des 512 (83) devrait être possible.

Ce qui est intéressant, c’est que vous pouvez utiliser différents superpositions de style pour différents aspects de votre thème. Ajoutez simplement quelques définitions de superposition pour colorAccent par exemple. Maintenant, vous pouvez combiner différentes valeurs pour la couleur primaire et la couleur d'accent presque arbitrairement.

Vous devez vous assurer que vos définitions de thème de superposition n'héritent pas accidentellement d'un ensemble de définitions de style d'une définition de style parent. Par exemple, un style appelé AppTheme.OverlayRed hérite implicitement de tous les styles définis dans AppTheme et toutes ces définitions seront également appliquées lorsque vous appliquez un correctif au thème principal. Donc évitez les points dans les noms de thème de superposition ou utilisez quelque chose comme Overlay.Red et définissez Overlay comme un style vide.

42
devconsole

J'ai créé une solution pour créer des thèmes de toutes les couleurs, peut-être que cela pourrait être utile à quelqu'un. API 9+

1. créez d'abord " res/values-v9/" et mettez il y a ce fichier: styles.xml et le dossier "res/values" habituel sera utilisé avec vos styles.

2. mettez ce code dans votre res/values ​​/ styles.xml:

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light">
        <item name="colorPrimary">#000</item>
        <item name="colorPrimaryDark">#000</item>
        <item name="colorAccent">#000</item>
        <item name="Android:windowAnimationStyle">@style/WindowAnimationTransition</item>
    </style>

    <style name="AppThemeDarkActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">#000</item>
        <item name="colorPrimaryDark">#000</item>
        <item name="colorAccent">#000</item>
        <item name="Android:windowAnimationStyle">@style/WindowAnimationTransition</item>
    </style>

    <style name="WindowAnimationTransition">
        <item name="Android:windowEnterAnimation">@Android:anim/fade_in</item>
        <item name="Android:windowExitAnimation">@Android:anim/fade_out</item>
    </style>
</resources>

3. dans AndroidManifest:

<application Android:theme="@style/AppThemeDarkActionBar">

4. créez une nouvelle classe avec le nom "ThemeColors.Java"

public class ThemeColors {

    private static final String NAME = "ThemeColors", KEY = "color";

    @ColorInt
    public int color;

    public ThemeColors(Context context) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(NAME, Context.MODE_PRIVATE);
        String stringColor = sharedPreferences.getString(KEY, "004bff");
        color = Color.parseColor("#" + stringColor);

        if (isLightActionBar()) context.setTheme(R.style.AppTheme);
        context.setTheme(context.getResources().getIdentifier("T_" + stringColor, "style", context.getPackageName()));
    }

    public static void setNewThemeColor(Activity activity, int red, int green, int blue) {
        int colorStep = 15;
        red = Math.round(red / colorStep) * colorStep;
        green = Math.round(green / colorStep) * colorStep;
        blue = Math.round(blue / colorStep) * colorStep;

        String stringColor = Integer.toHexString(Color.rgb(red, green, blue)).substring(2);
        SharedPreferences.Editor editor = activity.getSharedPreferences(NAME, Context.MODE_PRIVATE).edit();
        editor.putString(KEY, stringColor);
        editor.apply();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) activity.recreate();
        else {
            Intent i = activity.getPackageManager().getLaunchIntentForPackage(activity.getPackageName());
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            activity.startActivity(i);
        }
    }

    private boolean isLightActionBar() {// Checking if title text color will be black
        int rgb = (Color.red(color) + Color.green(color) + Color.blue(color)) / 3;
        return rgb > 210;
    }
}

5. et avant d'appeler setContentView (R.layout.activity_main) , il suffit d'ajouter:

new ThemeColors(this);

pour changer de couleur, remplacez Aléatoire par votre RVB:

    findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int red= new Random().nextInt(255);
            int green= new Random().nextInt(255);
            int blue= new Random().nextInt(255);
            ThemeColors.setNewThemeColor(MainActivity.this, red, green, blue);
        }
    });

enter image description here

19
IQ.feature

J'ai utilisé le code de Dahnark, mais j'ai également besoin de changer l'arrière-plan de la barre d'outils:

if (dark_ui) {
    this.setTheme(R.style.Theme_Dark);

    if (Build.VERSION.SDK_INT >= 21) {
        getWindow().setNavigationBarColor(getResources().getColor(R.color.Theme_Dark_primary));
        getWindow().setStatusBarColor(getResources().getColor(R.color.Theme_Dark_primary_dark));
    }
} else {
    this.setTheme(R.style.Theme_Light);
}

setContentView(R.layout.activity_main);

toolbar = (Toolbar) findViewById(R.id.app_bar);

if(dark_ui) {
    toolbar.setBackgroundColor(getResources().getColor(R.color.Theme_Dark_primary));
}
3
lgallard

Vous ne pouvez pas changer la couleur de colorPrimary, mais vous pouvez changer le thème de votre application en ajoutant un nouveau style avec une couleur différente.

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
</style>

<style name="AppTheme.NewTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/colorOne</item>
    <item name="colorPrimaryDark">@color/colorOneDark</item>
</style>

et à l'intérieur du thème de jeu d'activités

 setTheme(R.style.AppTheme_NewTheme);
 setContentView(R.layout.activity_main);
1
varghesekutty