Come posso creare ColorStateList a livello di codice?


158

Sto cercando di creare un ColorStateListprogramma utilizzando questo:

ColorStateList stateList = new ColorStateList(states, colors); 

Ma non sono sicuro di quali siano i due parametri.

Secondo la documentazione:

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

Aggiunto nel livello API 1

Crea un ColorStateList che restituisce la mappatura specificata dagli stati ai colori.

Qualcuno può spiegarmi come creare questo?

Qual è il significato della matrice bidimensionale per gli stati?

Risposte:


344

Vedi http://developer.android.com/reference/android/R.attr.html#state_above_anchor per un elenco degli stati disponibili.

Se vuoi impostare i colori per gli stati disabilitati, non focalizzati, non controllati ecc., Annulla semplicemente gli stati:

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
Grazie per le informazioni sugli stati "opposti"!
BVB

Questo può essere usato per cambiare il colore di un fab dalla libreria di design.
Tapirboy,

5
ATTENZIONE: vedere la risposta di Roger Alien (e il suo primo commento) per capire che l'ordine degli stati qui è scarso: poiché "abilitato" è il primo, sovrascriverà altri stati che si verificano in genere mentre un pulsante è abilitato. Meglio mettere "abilitato" per ultimo. (O invece di "abilitato", un oggetto vuoto / predefinito per ultimo.)
ToolmakerSteve

2
Un elenco di base degli stati di un pulsante che non trattiene lo stato (non un interruttore / casella di controllo) potrebbe essere {pressed}, {focused}, {-enabled}, {}. Per una ginocchiera che potrebbe essere {checked, pressed}, {pressed}, {checked, focused}, {focused}, {checked}, {-enabled}, {}. O una ginocchiera che ignora concentrarsi: {checked, pressed}, {pressed}, {checked}, {-enabled}, {}.
ToolmakerSteve

Nel caso in cui qualcuno proverà una di queste soluzioni, presta attenzione all'ordine che gli stati piacciono in selector.xml!
Anton Makov,

75

La prima dimensione è una matrice di insiemi di stati, la seconda è l'insieme di stati stesso. La matrice di colori elenca i colori per ogni serie di stati corrispondente, pertanto la lunghezza della matrice di colori deve corrispondere alla prima dimensione della matrice di stati (o si arresta in modo anomalo quando lo stato viene "utilizzato"). Ecco ed esempio:

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

spero che questo ti aiuti.

Esempio di EDIT: un elenco di stati di colore xml come:

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

sarebbe simile a questo

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

Puoi dire come rappresentare il seguente xml "<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 controlla la mia modifica, non l'ho ancora testata.
Su-Au Hwang,

3
Vale la pena dire che per specificare un falso stato, è possibile negarne il valore, quindi se si desidera specificare un colore per quando non viene premuto, è necessario utilizzare: new int [] {- ​​android.R.attr.state_pressed}
tinsukE

1
Per aggiungere a ciò che ha detto @tinsukE: Tuttavia, per evitare di sopprimere accidentalmente un elemento più avanti nell'elenco, per la maggior parte degli stati non ha senso mettere una negazione - invece gestire tutte le "altre" possibilità con un elemento predefinito (vuoto) new int[]{}ultimo - come mostrato nel blocco di codice finale di questa risposta. L'unico valore negato che utilizzo in genere è "abilitato". Un altro esempio, se si desidera tre colori diversi: "focalizzata + premuto", "focalizzata + non premuto", "premuto + non focalizzata", si può semplicemente mettere {focused, pressed}, {focused}, {pressed}. Verrà utilizzato il primo "vero".
ToolmakerSteve

2
... L'errore che si potrebbe fare è quello di avere una serie come {pressed}, {-pressed}, {focused}, {-focused}. Il problema è che {pressed}e {-pressed}coprire tutte le possibilità (il pulsante si sia premuto o non premuto), quindi non i colori elencati più avanti potrà mai essere utilizzato.!
ToolmakerSteve

64

A volte questo sarà sufficiente:

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

20

Sfortunatamente nessuna delle soluzioni funziona per me.

  1. Se all'inizio non si imposta lo stato premuto, non verrà rilevato.
  2. Se lo si imposta, è necessario definire lo stato vuoto per aggiungere il colore predefinito
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
        }
);

Questo è costruttore dal codice sorgente:

/**
 * 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
Proprio come un sidenote: devi trattarlo come se fossi un altro. Seleziona il primo stato che è vero. Pertanto, se si dispone di state_enabled come primo stato, verrà selezionato prima di state_pressed, a meno che la vista non sia disabilitata.
LeoFarage,

FWIW, dato che hai l'ultimo elemento predefinito, non credo che il primo elemento "abilitato" ti stia facendo del bene. Perché non rimuoverlo completamente?
ToolmakerSteve

18

Ecco un esempio di come creare un ColorListprogrammaticamente 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
        )
)

Inoltre, vedi la mia risposta di seguito per una funzione di supporto di Kotlin.
Arekolek,

7

Rimbalzando la risposta di Jonathan Ellis , in Kotlin puoi definire una funzione di aiuto per rendere il codice un po 'più idiomatico e più facile da leggere, quindi puoi invece scrivere questo:

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

colorStateListOf può essere implementato in questo modo:

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

Ho anche:

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

In modo che io possa chiamare lo stesso nome di funzione, non importa se si tratta di un selettore o di un singolo colore.


3

La mia classe builder per creare 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;
    }
}

Esempio di utilizzo

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 si utilizza la risorsa 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
come getResources()è deprecato, è ora ContextCompat.getColor(this,R.color.colorname);o ContextCompat.getColor(getActivity(),R.color.colorname);per l'uso in un frammento
iBobb

Per chiarire gli altri lettori new int[0](come elemento nell'elenco del primo parametro) è un array di lunghezza zero e rappresenta l'impostazione del colore predefinito. Qui è l'unico elemento, il che significa che la tinta viene applicata a tutti gli stati del pulsante. Ciò equivale a quanto new int[]{}visto nella risposta di Roger Alien.
ToolmakerSteve
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.