How do I create ColorStateList programmatically?

AndroidAndroid Color

Android Problem Overview


I am trying to create a ColorStateList programatically using this:

ColorStateList stateList = new ColorStateList(states, colors); 

But I am not sure what are the two parameters.

As per the documentation:

> public ColorStateList (int[][] states, int[] colors) > > Added in API level 1 > > Creates a ColorStateList that returns the specified mapping from states to colors.

Can somebody please explain me how to create this?

What is the meaning of two-dimensional array for states?

Android Solutions


Solution 1 - Android

See http://developer.android.com/reference/android/R.attr.html#state_above_anchor for a list of available states.

If you want to set colors for disabled, unfocused, unchecked states etc. just negate the states:

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

Solution 2 - Android

Sometimes this will be enough:

int colorInt = getResources().getColor(R.color.ColorVerificaLunes);
ColorStateList csl = ColorStateList.valueOf(colorInt);

Solution 3 - Android

The first dimension is an array of state sets, the second ist the state set itself. The colors array lists the colors for each matching state set, therefore the length of the colors array has to match the first dimension of the states array (or it will crash when the state is "used"). Here and example:

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

hope this helps.

EDIT example: a xml color state list like:

<?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>

would look like this

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

Solution 4 - Android

Here's an example of how to create a ColorList programmatically in 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
        )
)

Solution 5 - Android

Unfortunately none of the solutions works for me.

  1. If you don't set pressed state at first it won't detect it.
  2. If you set it, then you need to define empty state to add default color

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

This is constructor from source code:

/**
 * 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];
            }
        }
    }
}

Solution 6 - Android

Bouncing off the answer by Jonathan Ellis, in Kotlin you can define a helper function to make the code a bit more idiomatic and easier to read, so you can write this instead:

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

colorStateListOf can be implemented like this:

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

I also have:

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

So that I can call the same function name, no matter if it's a selector or single color.

Solution 7 - Android

My builder class for create 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;
    }
}

Example Using

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

Solution 8 - Android

if you use the resource the 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);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnukoolView Question on Stackoverflow
Solution 1 - AndroidCanerView Answer on Stackoverflow
Solution 2 - AndroidtseView Answer on Stackoverflow
Solution 3 - AndroidSu-Au HwangView Answer on Stackoverflow
Solution 4 - AndroidJonathan EllisView Answer on Stackoverflow
Solution 5 - AndroidRoger AlienView Answer on Stackoverflow
Solution 6 - AndroidarekolekView Answer on Stackoverflow
Solution 7 - AndroidLinhView Answer on Stackoverflow
Solution 8 - AndroidDavid HackroView Answer on Stackoverflow