Comment créer ColorStateList par programmation?

158

J'essaie de créer un ColorStateListprogramme en utilisant ceci:

ColorStateList stateList = new ColorStateList(states, colors); 

Mais je ne sais pas quels sont les deux paramètres.

Selon la documentation:

public ColorStateList (int[][] states, int[] colors) 

Ajouté au niveau d'API 1

Crée un ColorStateList qui renvoie le mappage spécifié des états aux couleurs.

Quelqu'un peut-il m'expliquer comment créer cela?

Quelle est la signification d'un tableau à deux dimensions pour les états?

Anukool
la source

Réponses:

344

Voir http://developer.android.com/reference/android/R.attr.html#state_above_anchor pour une liste des états disponibles.

Si vous souhaitez définir des couleurs pour les états désactivés, non focalisés, non cochés, etc., annulez simplement les états:

int[][] states = new int[][] {
    new int[] { android.R.attr.state_enabled}, // enabled
    new int[] {-android.R.attr.state_enabled}, // disabled
    new int[] {-android.R.attr.state_checked}, // unchecked
    new int[] { android.R.attr.state_pressed}  // pressed
};

int[] colors = new int[] {
    Color.BLACK,
    Color.RED,
    Color.GREEN,
    Color.BLUE
};

ColorStateList myList = new ColorStateList(states, colors);
Caner
la source
45
Merci pour les informations concernant les états "opposés"!
BVB
Cela peut être utilisé pour changer la couleur d'une fab à partir de la bibliothèque de conception.
Tapirboy
5
ATTENTION: Voir la réponse de Roger Alien (et son premier commentaire) pour comprendre que l'ordre des états ici est médiocre: parce que «activé» est le premier, il remplacera les autres états qui se produisent généralement lorsqu'un bouton est activé. Mieux vaut mettre "activé" en dernier. (Ou au lieu de "activé", un élément vide / par défaut en dernier.)
ToolmakerSteve
2
Une liste de base des états pour un bouton qui ne retient pas l' état (pas une bascule / case à cocher) pourrait être {pressed}, {focused}, {-enabled}, {}. Pour une bascule , il est peut - être {checked, pressed}, {pressed}, {checked, focused}, {focused}, {checked}, {-enabled}, {}. Ou une bascule qui ne tient pas mise au point: {checked, pressed}, {pressed}, {checked}, {-enabled}, {}.
ToolmakerSteve
Au cas où quelqu'un essaierait l'une de ces solutions, faites attention à l'ordre des états comme dans selector.xml!
Anton Makov
75

La première dimension est un tableau d'ensembles d'états, la seconde est l'ensemble d'états lui-même. Le tableau de couleurs répertorie les couleurs pour chaque ensemble d'états correspondant, par conséquent, la longueur du tableau de couleurs doit correspondre à la première dimension du tableau d'états (ou il se plantera lorsque l'état est "utilisé"). Ici et exemple:

ColorStateList myColorStateList = new ColorStateList(
                        new int[][]{
                                new int[]{android.R.attr.state_pressed}, //1
                                new int[]{android.R.attr.state_focused}, //2
                                new int[]{android.R.attr.state_focused, android.R.attr.state_pressed} //3
                        },
                        new int[] {
                            Color.RED, //1
                            Color.GREEN, //2
                            Color.BLUE //3
                        }
                    );

J'espère que cela t'aides.

Exemple EDIT: une liste d'états de couleurs xml comme:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:color="@color/white"/>
    <item android:color="@color/black"/>
</selector>

ressemblerait à ça

ColorStateList myColorStateList = new ColorStateList(
        new int[][]{
                new int[]{android.R.attr.state_pressed},
                new int[]{}
        },
        new int[] {
                context.getResources().getColor(R.color.white),
                context.getResources().getColor(R.color.black)
        }
);
Su-Au Hwang
la source
Pouvez-vous dire comment représenter le xml ci-dessous "<selector xmlns: android =" schemas.android.com/apk/res/android "> <item android: state_pressed =" true "android: color =" @ color / white "/ > <item android: color = "@ color / black" /> </selector> "en utilisant colorstatelist.
Satish
@SatishKumar vérifie ma modification, je ne l'ai pas testée cependant.
Su-Au Hwang
3
Cela vaut la peine de dire que pour spécifier un état faux, vous pouvez annuler sa valeur, donc si vous voulez spécifier une couleur pour quand elle n'est pas pressée, vous devez utiliser: new int [] {- ​​android.R.attr.state_pressed}
tinsukE
1
Pour ajouter à ce que @tinsukE a dit: Cependant, pour éviter de supprimer accidentellement un élément plus tard dans la liste, pour la plupart des états, il ne sera pas logique de mettre une négation - à la place, gérez toutes les «autres» possibilités avec un élément par défaut (vide) new int[]{}dernier - comme indiqué dans le bloc de code final de cette réponse. La seule valeur annulée que j'utilise généralement est "-enabled". Un autre exemple, si vous voulez trois couleurs différentes: « concentré + pressé », « concentré + non pressé », « pressé + pas concentré », vous pouvez tout simplement {focused, pressed}, {focused}, {pressed}. Le premier "vrai" sera utilisé.
ToolmakerSteve
2
... L'erreur que vous pourriez faire est d'avoir une série comme {pressed}, {-pressed}, {focused}, {-focused}. Le problème est que {pressed}et {-pressed}couvre TOUTES les possibilités (le bouton est enfoncé ou non), donc aucune couleur répertoriée plus tard ne sera jamais utilisée.!
ToolmakerSteve
65

Parfois, cela suffira:

int colorInt = getResources().getColor(R.color.ColorVerificaLunes);
ColorStateList csl = ColorStateList.valueOf(colorInt);
tse
la source
20

Malheureusement, aucune des solutions ne fonctionne pour moi.

  1. Si vous ne définissez pas l'état pressé au début, il ne le détectera pas.
  2. Si vous le définissez, vous devez définir l'état vide pour ajouter la couleur par défaut
ColorStateList themeColorStateList = new ColorStateList(
        new int[][]{
                new int[]{android.R.attr.state_pressed},
                new int[]{android.R.attr.state_enabled},
                new int[]{android.R.attr.state_focused, android.R.attr.state_pressed},
                new int[]{-android.R.attr.state_enabled},
                new int[]{} // this should be empty to make default color as we want
        },
        new int[]{
                pressedFontColor,
                defaultFontColor,
                pressedFontColor,
                disabledFontColor,
                defaultFontColor
        }
);

C'est le constructeur du code source:

/**
 * Creates a ColorStateList that returns the specified mapping from
 * states to colors.
 */
public ColorStateList(int[][] states, int[] colors) {
    mStateSpecs = states;
    mColors = colors;

    if (states.length > 0) {
        mDefaultColor = colors[0];

        for (int i = 0; i < states.length; i++) {
            if (states[i].length == 0) {
                mDefaultColor = colors[i];
            }
        }
    }
}
Roger Alien
la source
5
Juste comme une remarque: vous devez le traiter comme vous le feriez avec un if-elseif. Il sélectionne le premier état qui est vrai. Donc, si vous avez le state_enabled comme premier état, il sera sélectionné avant state_pressed - sauf si la vue est désactivée.
LeoFarage
FWIW, puisque vous avez un élément par défaut en dernier, je ne pense pas que le premier élément "activé" vous fasse du bien. Pourquoi ne pas le supprimer complètement?
ToolmakerSteve
18

Voici un exemple de création d'un ColorListprogramme par programme dans Kotlin:

val colorList = ColorStateList(
        arrayOf(
                intArrayOf(-android.R.attr.state_enabled),  // Disabled
                intArrayOf(android.R.attr.state_enabled)    // Enabled
        ),
        intArrayOf(
                Color.BLACK,     // The color for the Disabled state
                Color.RED        // The color for the Enabled state
        )
)
Jonathan Ellis
la source
Voir également ma réponse ci-dessous pour une fonction d'assistance Kotlin.
arekolek le
7

Rebondissant sur la réponse de Jonathan Ellis , dans Kotlin, vous pouvez définir une fonction d'assistance pour rendre le code un peu plus idiomatique et plus facile à lire, vous pouvez donc écrire ceci à la place:

val colorList = colorStateListOf(
    intArrayOf(-android.R.attr.state_enabled) to Color.BLACK,
    intArrayOf(android.R.attr.state_enabled) to Color.RED
)

colorStateListOf peut être implémenté comme ceci:

fun colorStateListOf(vararg mapping: Pair<IntArray, Int>): ColorStateList {
    val (states, colors) = mapping.unzip()
    return ColorStateList(states.toTypedArray(), colors.toIntArray())
}

J'ai aussi:

fun colorStateListOf(@ColorInt color: Int): ColorStateList {
    return ColorStateList.valueOf(color)
}

Pour que je puisse appeler le même nom de fonction, qu'il s'agisse d'un sélecteur ou d'une seule couleur.

Arekolek
la source
3

Ma classe de constructeur pour créer ColorStateList

private class ColorStateListBuilder {
    List<Integer> colors = new ArrayList<>();
    List<int[]> states = new ArrayList<>();

    public ColorStateListBuilder addState(int[] state, int color) {
        states.add(state);
        colors.add(color);
        return this;
    }

    public ColorStateList build() {
        return new ColorStateList(convertToTwoDimensionalIntArray(states),
                convertToIntArray(colors));
    }

    private int[][] convertToTwoDimensionalIntArray(List<int[]> integers) {
        int[][] result = new int[integers.size()][1];
        Iterator<int[]> iterator = integers.iterator();
        for (int i = 0; iterator.hasNext(); i++) {
            result[i] = iterator.next();
        }
        return result;
    }

    private int[] convertToIntArray(List<Integer> integers) {
        int[] result = new int[integers.size()];
        Iterator<Integer> iterator = integers.iterator();
        for (int i = 0; iterator.hasNext(); i++) {
            result[i] = iterator.next();
        }
        return result;
    }
}

Exemple d'utilisation

ColorStateListBuilder builder = new ColorStateListBuilder();
builder.addState(new int[] { android.R.attr.state_pressed }, ContextCompat.getColor(this, colorRes))
       .addState(new int[] { android.R.attr.state_selected }, Color.GREEN)
       .addState(..., some color);

if(// some condition){
      builder.addState(..., some color);
}
builder.addState(new int[] {}, colorNormal); // must add default state at last of all state

ColorStateList stateList = builder.build(); // ColorStateList created here

// textView.setTextColor(stateList);
Phan Van Linh
la source
2

si vous utilisez la ressource Colors.xml

int[] colors = new int[] {
                getResources().getColor(R.color.ColorVerificaLunes),
                getResources().getColor(R.color.ColorVerificaMartes),
                getResources().getColor(R.color.ColorVerificaMiercoles),
                getResources().getColor(R.color.ColorVerificaJueves),
                getResources().getColor(R.color.ColorVerificaViernes)

        };

ColorStateList csl = new ColorStateList(new int[][]{new int[0]}, new int[]{colors[0]}); 

    example.setBackgroundTintList(csl);
David Hackro
la source
2
tel qu'il getResources()est obsolète, il l'est maintenant ContextCompat.getColor(this,R.color.colorname);ou ContextCompat.getColor(getActivity(),R.color.colorname);pour une utilisation dans un fragment
iBobb
Pour clarifier pour les autres lecteurs, new int[0](en tant qu'élément dans la liste du premier paramètre) est un tableau de longueur nulle et représente la définition de la couleur par défaut. Ici, c'est le seul élément, ce qui signifie que la teinte est appliquée à tous les états du bouton. C'est l'équivalent de new int[]{}la réponse de Roger Alien.
ToolmakerSteve