Como crio ColorStateList programaticamente?


158

Estou tentando criar um ColorStateListprogramaticamente usando isso:

ColorStateList stateList = new ColorStateList(states, colors); 

Mas não tenho certeza de quais são os dois parâmetros.

Conforme a documentação:

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

Adicionado no nível 1 da API

Cria um ColorStateList que retorna o mapeamento especificado dos estados para as cores.

Alguém pode me explicar como criar isso?

Qual é o significado da matriz bidimensional para estados?

Respostas:


343

Consulte http://developer.android.com/reference/android/R.attr.html#state_above_anchor para obter uma lista dos estados disponíveis.

Se você deseja definir cores para estados desabilitados, sem foco, desmarcados etc., apenas negue os estados:

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

45
Obrigado pela informação sobre estados "opostos"!
BVB 07/01

Isso pode ser usado para alterar a cor de uma manufatura da biblioteca de projetos.
Tapirboy

5
CUIDADO: Consulte a resposta de Roger Alien (e seu primeiro comentário) para entender que a ordem dos estados aqui é ruim: como "enabled" é o primeiro, ele substituirá outros estados que normalmente ocorrem enquanto um botão está ativado. Melhor colocar "ativado" por último. (Ou em vez de "ativado", um item / default vazio passado.)
ToolmakerSteve

2
A lista básica de estados para um botão que não retenha estado (não um alternar / caixa) pode ser {pressed}, {focused}, {-enabled}, {}. Para uma alternância pode ser {checked, pressed}, {pressed}, {checked, focused}, {focused}, {checked}, {-enabled}, {}. Ou uma alternância que ignora foco: {checked, pressed}, {pressed}, {checked}, {-enabled}, {}.
Home

Caso alguém tente alguma dessas soluções, preste atenção na ordem em que os estados estão no selector.xml!
Anton Makov

75

A primeira dimensão é uma matriz de conjuntos de estados, a segunda é o próprio conjunto de estados. A matriz de cores lista as cores de cada conjunto de estados correspondentes; portanto, o comprimento da matriz de cores deve corresponder à primeira dimensão da matriz de estados (ou será interrompida quando o estado for "usado"). Aqui e exemplo:

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

espero que isto ajude.

Exemplo de edição: uma lista de estados de cores xml como:

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

ficaria assim

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

Você pode dizer como representar o xml abaixo "<selector xmlns: android =" schemas.android.com/apk/res/android "> <item android: state_pressed =" true "android: color =" @ color / white "/ > <item android: color = "@ color / black" /> </selector> "usando colorstatelist.
Satish

@SatishKumar verifica minha edição, mas ainda não testei.
Su-Au Hwang

3
Vale dizer que, para especificar um estado falso, você pode negar seu valor; portanto, se desejar especificar uma cor para quando não for pressionada, use: new int [] {- ​​android.R.attr.state_pressed}
tinsukE

1
Para adicionar o que o @tinsukE disse: No entanto, para evitar a supressão acidental de um item posteriormente na lista, para a maioria dos estados não faz sentido colocar uma negação - em vez disso, lide com todas as "outras" possibilidades com um item padrão (vazio) new int[]{}last - como mostrado no bloco de código final desta resposta. O único valor negado que normalmente uso é "-enabled". Outro exemplo, se você quiser três cores diferentes: "focado + pressionado", "focado + não pressionado", "pressionada + não focado", você pode simplesmente colocar {focused, pressed}, {focused}, {pressed}. O primeiro "verdadeiro" será usado.
Home

2
... O erro que você pode fazer é ter uma série como {pressed}, {-pressed}, {focused}, {-focused}. O problema é esse {pressed}e {-pressed}abrange TODAS as possibilidades (o botão é pressionado ou não pressionado), para que nenhuma cor listada mais tarde seja usada.
Página

64

Às vezes isso será suficiente:

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

20

Infelizmente, nenhuma das soluções funciona para mim.

  1. Se você não definir o estado pressionado no início, ele não será detectado.
  2. Se você configurá-lo, precisará definir o estado vazio para adicionar a cor padrão
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
        }
);

Este é o construtor do código fonte:

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

5
Como nota de rodapé: você deve tratá-lo como se fosse um if-elseif. Ele seleciona o primeiro estado que é verdadeiro. Portanto, se você tiver o state_enabled como primeiro estado, ele será selecionado antes do state_pressed - a menos que a visualização esteja desativada.
LeoFarage

FWIW, como você tem um elemento padrão por último, não acho que o primeiro elemento "ativado" esteja lhe fazendo bem algum. Por que não removê-lo completamente?
Home

18

Aqui está um exemplo de como criar uma ColorListprogramação no 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
        )
)

Além disso, veja minha resposta abaixo para uma função auxiliar do Kotlin.
arekolek

7

Rendendo a resposta de Jonathan Ellis , no Kotlin, você pode definir uma função auxiliar para tornar o código um pouco mais idiomático e mais fácil de ler, para que você possa escrever isso:

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

colorStateListOf pode ser implementado assim:

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

Eu também tenho:

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

Para que eu possa chamar o mesmo nome da função, não importa se é um seletor ou uma cor única.


3

Minha classe de construtor para 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;
    }
}

Exemplo de uso

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

2

se você usar o recurso 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);

2
como getResources()está obsoleta, é agora ContextCompat.getColor(this,R.color.colorname);ou ContextCompat.getColor(getActivity(),R.color.colorname);para uso em um fragmento
iBobb

Para esclarecer para outros leitores, new int[0](como um elemento na lista do primeiro parâmetro) é uma matriz de comprimento zero e representa a configuração da cor padrão. Aqui é o único elemento, o que significa que a tonalidade é aplicada a todos os estados do botão. Isso é equivalente ao new int[]{}visto na resposta de Roger Alien.
usar o seguinte
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.